package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.StageProcessEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.StageTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.MultiUnitItemPoJo;
import com.xbongbong.paas.field.SaasParticularAttributePoJo;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataValidateProductHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.ProUpdateHelp;
import com.xbongbong.paas.help.SaasStageHelp;
import com.xbongbong.paas.help.StageLogHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.StageProcessModel;
import com.xbongbong.paas.pojo.AttrValuePojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.ProductFieldPojo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.AggSumDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.FormDataSummaryDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.AggSumVO;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.CustomerRuleService;
import com.xbongbong.paas.service.PaasFormService;
import com.xbongbong.paas.service.TransferBackRuleScriptService;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.log.crm.help.OperationLogHelp;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.interfaces.logger.OperationLogFactory;
import com.xbongbong.parent.interfaces.logger.OperationLogHandle;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.businessdata.pojo.dto.FocusDTO;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.businessproduct.pojo.dto.BusinessProductListDTO;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.customer.pojo.dto.CustomerRestoreBatchDTO;
import com.xbongbong.pro.customercommunicate.pojo.dto.CustomerDynamicAddDTO;
import com.xbongbong.pro.defaultData.pojo.DefaultDataPojo;
import com.xbongbong.pro.defaultData.pojo.dto.DefaultDataDTO;
import com.xbongbong.pro.defaultData.pojo.vo.DefaultDataVO;
import com.xbongbong.pro.detailtab.vo.ProductSummaryVO;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.AfterSavePojo;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteBatchOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.log.pojo.dto.UpdateBatchOperationLogDTO;
import com.xbongbong.pro.message.constant.OpportunityPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.opportunity.pojo.JudgeStageChangedPojo;
import com.xbongbong.pro.opportunity.pojo.dto.OpportunityDeleteBatchDTO;
import com.xbongbong.pro.opportunity.pojo.dto.OpportunityEditAttrUpdateDTO;
import com.xbongbong.pro.opportunity.pojo.dto.OpportunityUpdateBatchDTO;
import com.xbongbong.pro.opportunity.pojo.dto.OpportunityUpdateByBusinessRuleDTO;
import com.xbongbong.pro.opportunity.pojo.dto.OpportunityUpdateDTO;
import com.xbongbong.pro.opportunity.pojo.vo.OpportunityDeleteBatchVO;
import com.xbongbong.pro.opportunity.pojo.vo.OpportunityNextStageVO;
import com.xbongbong.pro.opportunity.pojo.vo.OpportunityUpdateBatchVO;
import com.xbongbong.pro.opportunity.pojo.vo.OpportunityUpdateByBusinessRuleVO;
import com.xbongbong.pro.opportunitystagelog.pojo.dto.OpportunityStageLogInsertDTO;
import com.xbongbong.pro.opportunityuser.pojo.dto.OpportunityUserDeleteBatchDTO;
import com.xbongbong.pro.product.pojo.dto.PagingProductDTO;
import com.xbongbong.pro.product.pojo.vo.DetailProductVO;
import com.xbongbong.pro.product.pojo.vo.PagingProductVO;
import com.xbongbong.pro.pushnotify.dto.PushNotifyDeleteDTO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.analytical.impl.OpportunityValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CustomerUserEntity;
import com.xbongbong.saas.domain.entity.OpportunityFocusEntity;
import com.xbongbong.saas.domain.entity.OpportunityProductEntity;
import com.xbongbong.saas.domain.entity.OpportunityStageLogEntity;
import com.xbongbong.saas.domain.entity.OpportunityUserEntity;
import com.xbongbong.saas.domain.entity.SaleStageEntity;
import com.xbongbong.saas.domain.entity.StaticForUpdateDTO;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.competitor.CompetitorAnalysisEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.OpportunityEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.BusinessProductEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperatePageEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.RelativeProductEnum;
import com.xbongbong.saas.enums.RuleSettingEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.UpdateDataTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryTermEnum;
import com.xbongbong.saas.enums.product.OpportunityProductEnum;
import com.xbongbong.saas.enums.subform.CustomerTeamEnum;
import com.xbongbong.saas.help.CompetitorHelp;
import com.xbongbong.saas.help.ExplainHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.RelativeProductHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaasFormHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.help.workflow.MarketActivityForStaticHelp;
import com.xbongbong.saas.model.CompetitorAnalysisModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.CustomerUserModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.OpportunityFocusModel;
import com.xbongbong.saas.model.OpportunityModel;
import com.xbongbong.saas.model.OpportunityProductModel;
import com.xbongbong.saas.model.OpportunityStageLogModel;
import com.xbongbong.saas.model.OpportunityUserModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.SaleStageModel;
import com.xbongbong.saas.model.SpecificationModel;
import com.xbongbong.saas.model.StageWorkModel;
import com.xbongbong.saas.model.impl.DataDictionaryModelImpl;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.OpportunityService;
import com.xbongbong.saas.service.OpportunityUserService;
import com.xbongbong.saas.service.PushNotifyService;
import com.xbongbong.saas.service.QuotationService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static com.xbongbong.saas.enums.RelativeProductEnum.BARCODE;
import static com.xbongbong.saas.enums.RelativeProductEnum.NAME;
import static com.xbongbong.saas.enums.RelativeProductEnum.NUM;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCT_NO;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCT_PRICE;
import static com.xbongbong.saas.enums.RelativeProductEnum.SALE_DISCOUNT;
import static com.xbongbong.saas.enums.RelativeProductEnum.SALE_PRODUCT_PRICE;
import static com.xbongbong.saas.enums.RelativeProductEnum.SPECIFICATION;
import static com.xbongbong.saas.enums.RelativeProductEnum.SUBTOTAL;
import static com.xbongbong.saas.enums.RelativeProductEnum.UNIT;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author long.rao
 * @version v1.0
 * @date 2019/1/22 9:01
 * @since v1.0
 */
@Service("opportunityService")
public class OpportunityServiceImpl implements OpportunityService {

    private static final Logger LOG = LoggerFactory.getLogger(OpportunityServiceImpl.class);

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private ProUpdateHelp proUpdateHelp;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private CustomerUserModel customerUserModel;
    @Resource
    private UserModel userModel;
    @Resource
    private OpportunityUserModel opportunityUserModel;
    @Resource
    private OpportunityModel opportunityModel;
    @Resource
    private OpportunityFocusModel opportunityFocusModel;
    @Resource
    private OpportunityProductModel opportunityProductModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private SpecificationModel specificationModel;
    @Resource
    private ExplainHelp explainHelp;
    @Resource
    private OpportunityUserService opportunityUserService;
    @Resource
    private SaleStageModel saleStageModel;
    @Resource
    @Lazy
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PushNotifyService pushNotifyService;
    @Resource
    private DataDictionaryModelImpl dataDictionaryModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private CustomerRuleService customerRuleService;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private QuotationService quotationService;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private FormDataValidateProductHelp formDataValidateProductHelp;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaasFormHelp saasFormHelp;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private PaasFormService paasFormService;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private RelativeProductHelp relativeProductHelp;
    @Resource
    private OpportunityValidateAnalyticalServiceImpl opportunityAnalyticalService;
    @Resource
    private StageLogHelp stageLogHelp;
    @Resource
    private StageProcessModel stageProcessModel;
    @Resource
    private OpportunityStageLogModel opportunityStageLogModel;
    @Resource
    private StageWorkModel stageWorkModel;
    @Resource
    private SaasStageHelp saasStageHelp;
    @Resource
    private OperationLogFactory operationLogFactory;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private TransferBackRuleScriptService transferBackRuleScriptService;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private MarketActivityForStaticHelp marketActivityForStaticHelp;
    @Resource
    private TransactionHelp transactionHelp;
    @Resource
    private CompetitorAnalysisModel competitorAnalysisModel;
    @Resource
    private CompetitorHelp competitorHelp;

    /**
     * 销售机会保存前saas特殊校验
     *
     * @param validateDataDTO saas特殊校验数据入参
     * @throws XbbException 业务异常
     * @author long.rao
     * @date 2019-01-23 10:14
     */
    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        opportunityAnalyticalService.beforeSave(validateDataDTO);
    }



    /**
     * 销售机会保存后逻辑
     *
     * @param saasFormSaveDTO saas特殊校验数据入参
     * @throws XbbException 业务异常
     * @author long.rao
     * @date 2019-01-23 10:16
     */
    @Override
    public AfterSavePojo afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        AfterSavePojo afterSavePojo = new AfterSavePojo();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Integer subBusiniessType = saasFormSaveDTO.getSubBusinessType();
        Long oppId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        JSONObject newData = newPaasFormDataEntity.getData();
        Long formId = newPaasFormDataEntity.getFormId();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(newData, SalesOpportunityEnum.CUSTOMER_NAME.getAttr(), 0L);
        String salesStageCode = FastJsonHelper.getStringOrDefaultFromFormData(newData, SalesOpportunityEnum.SALE_STAGE.getAttr(), "");
        Integer reasonId = getIntegerOrDefaultFromFormData(newData, SalesOpportunityEnum.WASTAGE.getAttr(), BasicConstant.ZERO);
        String wastageMemo = FastJsonHelper.getStringOrDefaultFromFormData(newData, SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), "");
        String opportunityName = FastJsonHelper.getStringOrDefaultFromFormData(newData, SalesOpportunityEnum.NAME.getAttr(), "");
        Long stageId = FastJsonHelper.getLongOrDefaultFromFormData(newData, SalesOpportunityEnum.STAGE_ID.getAttr(), BasicConstant.ZERO_LONG);
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
        // 新建的时候阶段不为空或者编辑时阶段不一致才需要更改阶段
        JudgeStageChangedPojo judgeStageChangedPojo = stageLogHelp.judgeStageChanged(corpid, formId, oppId, salesStageCode, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        if (judgeStageChangedPojo.getIsStageChanged()) {
            try {
                saasStageHelp.stageJump(saasFormSaveDTO, SalesOpportunityEnum.SALE_STAGE.getAttr());
            } catch (Exception e) {
                LOG.error("销售阶段变更消息推送", e);
            }
        }
        try {
            // 团队保存
            afterSavePojo = teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), oppId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), false);
        } catch (XbbException e) {
            LOG.warn("机会保存协同团队", e);
            throw e;
        }
        Runnable runnable = () -> {
            String creatorId = newPaasFormDataEntity.getCreatorId();
            UserEntity creatorUser = userModel.getByKey(creatorId, corpid);
            String creatorUserName = Objects.isNull(creatorUser) ? "" : creatorUser.getName();
            if (isNew) {
                CustomerEntityExt customerEntity = customerModel.getByKey(customerId, corpid);
                boolean customerNonNull = Objects.nonNull(customerEntity);
                try {
                    // 新建更新客户最后联系时间
                    long lastConnectTime = DateUtil.getInt();
                    if (customerNonNull) {
                        //新建销售机会，取其创建时间更新影响客户最后跟进时间
                        Boolean flag = paasFormService.getSingleRuleList(corpid, RuleSettingEnum.NEW_OPPORTUNITIES_CREATE_TIME.getConfig(), customerEntity.getFormId());
                        if (flag) {
                            proUpdateHelp.jsonSetSetValueIntoFormDataById(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), corpid, customerId,
                                    CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), CustomerManagementEnum.LAST_CONNECT_TIME.getFieldType(), lastConnectTime);
                        }

                        //更新最近机会创建时间
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put(CustomerManagementEnum.OPPORTUNITY_ADD_DATE.getAttr(),lastConnectTime);
                        customerModel.specialUpdate4SysDate(customerId, jsonObject, corpid);
                    } else {
                        LOG.warn("新建机会更新客户最后联系时间,客户数据没查到 corpid={},customerId={},oppId={}", corpid, customerId, oppId);
                    }
                } catch (Exception e) {
                    LOG.error("新建机会更新客户最后联系时间", e);
                }

                try {
                    // 去除客户标签
                    boolean customerSeniorModel = commonHelp.isCustomerPublicPoolSeniorModel(corpid);
                    Long customerFormId  = customerNonNull ? customerEntity.getFormId() : 0L;
                    if (customerSeniorModel){
                        transferBackRuleScriptService.deletePublicSeniorTag(corpid,Collections.singletonList(customerId),XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(),customerFormId);
                    }else {
                        customerRuleService.deletePublicTag(corpid, Collections.singletonList(customerId));
                    }
                } catch (Exception e) {
                    LOG.error("新建机会动态去除客户标签", e);
                }

                try {
                    if (Objects.equals(subBusiniessType, XbbRefTypeEnum.KEY_OPPORTUNITY.getCode())) {
                        // 重点机会关注
                        if (Objects.equals(saasFormSaveDTO.getSubBusinessType(), XbbRefTypeEnum.KEY_OPPORTUNITY.getCode())) {
                            FocusDTO focusDTO = new FocusDTO();
                            focusDTO.setBusinessType(saasFormSaveDTO.getBusinessType());
                            focusDTO.setCorpid(saasFormSaveDTO.getCorpid());
                            focusDTO.setUserId(saasFormSaveDTO.getUserId());
                            focusDTO.setDataIdList(Collections.singletonList(oppId));
                            focusDTO.setFocus(1);
                            focus(focusDTO);
                        }
                    }
                } catch (Exception e) {
                    LOG.error("新建机会重点机会关注", e);
                }

                // 机会新建动态
                try {
                    if(customerNonNull) {
                        if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                            // 机会创建项目日志
                            CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
                            String customerName = newData.getString(SalesOpportunityEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
                            String operate = Objects.equals(saasFormSaveDTO.getIsImport(), 1) ? I18nMessageUtil.getMessage(I18nStringConstant.IMPORTED) : I18nMessageUtil.getMessage(I18nStringConstant.ADD);
                            String communicateMemo = "“" + creatorUser.getName() + "”" + operate + I18nMessageUtil.getMessage(I18nStringConstant.A_SALES_OPPORTUNITY) + "“" + newPaasFormDataEntity.getSerialNo() + "”";
                            String saleStage = newData.getString(SalesOpportunityEnum.SALE_STAGE.getAttr());
                            customerDynamicAddDTO.setCorpid(corpid);
                            customerDynamicAddDTO.setUserId(creatorId);
                            customerDynamicAddDTO.setCustomerId(customerId);
                            customerDynamicAddDTO.setCustomerName(customerName);
                            customerDynamicAddDTO.setMemo(communicateMemo);
                            if (Objects.nonNull(saleStage)) {
                                List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                                for (FieldAttrEntity fieldAttrEntity : explainList) {
                                    if (Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.SALE_STAGE.getAttr())) {
                                        List<ItemPoJo> items = fieldAttrEntity.getItems();
                                        if (CollectionsUtil.isNotEmpty(items)) {
                                            for (ItemPoJo item : items) {
                                                if (item.getValue().equals(saleStage)) {
                                                    String memo = communicateMemo.concat("," + String.format(I18nMessageUtil.getMessage(I18nStringConstant.STAGE_LOG),
                                                            I18nMessageUtil.getMessage(DictionaryTermEnum.SALE_STAGE.getName()), item.getText()));
                                                    customerDynamicAddDTO.setMemo(memo);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            customerDynamicAddDTO.setCommunicateBusinessText(newPaasFormDataEntity.getSerialNo());
                            customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                            customerDynamicAddDTO.setDataId(oppId);
                            customerDynamicAddDTO.setLogType(ProjectLogEnum.OPPORTUNITY_CREATE.getSubType());
                            customerDynamicAddDTO.setDistributorMark(DistributorMarkEnum.DISTRIBUTOR.getCode());
                            customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
                        } else {
                            DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategy(ProjectLogEnum.OPPORTUNITY_CREATE.getSubType());
                            transactionHelp.afterCommitOrCommitNow(p -> {
                                dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(oppId, formId, saasFormSaveDTO, creatorUser, judgeStageChangedPojo));
                            });
                        }
                    }
                } catch (Exception e) {
                    LOG.error("机会创建动态失败：", e);
                }

                try {
                    if (!Objects.equals(saasFormSaveDTO.getIsImport(), 1)) {
                        // 新建销售机会消息推送
                        OpportunityEntityExt opportunityEntityExt = new OpportunityEntityExt();
                        BeanUtil.copyProperties(newPaasFormDataEntity, opportunityEntityExt);
                        List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.OPPORTUNITY_ADD_PUSH.getCode(), PushTypeEnum.OPPORTUNITY_ADD_PUSH.getSubCode(), creatorUser, opportunityEntityExt);
                        PushRefTypePojo.Options options = new PushRefTypePojo.Options(newPaasFormDataEntity.getAppId(), newPaasFormDataEntity.getMenuId(), newPaasFormDataEntity.getFormId(), oppId, Collections.singletonList(oppId), SaasMarkEnum.SAAS.getCode(), saasFormSaveDTO.getBusinessType(), saasFormSaveDTO.getSubBusinessType());
                        MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(oppId), 0, null, I18nMessageUtil.getMessage(OpportunityPushConstant.OPPORTUNITY_ADD_TITLE), String.format(I18nMessageUtil.getMessage(OpportunityPushConstant.OPPORTUNITY_ADD_CONTENT), creatorUser.getName(), newPaasFormDataEntity.getSerialNo()), null, options);
                        baseProducer.sendMessage(PushTypeEnum.OPPORTUNITY_ADD_PUSH, messageRabbitMqDTO);
                    }
                } catch (Exception e) {
                    LOG.error("新建销售机会消息推送", e);
                }
            }

            if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(SalesOpportunityEnum.PRODUCTS.getAttr())) {
                try {
                    JSONArray productArray = newPaasFormDataEntity.getData().getJSONArray(SalesOpportunityEnum.PRODUCTS.getAttr());
//                saveProduct(productArray, corpid, oppId, saasFormSaveDTO.getIsImport());
                    saveProduct2(productArray, corpid, oppId, isNew,newPaasFormDataEntity.getFormId());
                } catch (Exception e) {
                    LOG.error("保存机会关联产品", e);
                }
            }

        };
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);

        return afterSavePojo;
    }

    private void saveProduct2(JSONArray productArray, String corpid, Long oppId, Boolean isNew, Long formId) throws XbbException {
        Map<Long,OpportunityProductEntity> originProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,OpportunityProductEntity> approveFailedProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!isNew){
            List<OpportunityProductEntity> dbList = opportunityProductModel.getProductsByOppId(oppId, corpid, Arrays.asList(DelEnum.NORMAL.getDel(), DelEnum.APPROVE_FAILED.getDel()));
            dbList.forEach(item -> {
                originProductMap.put(item.getId(),item);
                if (Objects.equals(item.getDel(), DelEnum.APPROVE_FAILED.getDel())) {
                    approveFailedProductMap.put(item.getId(),item);
                }
            });
        }
        List<OpportunityProductEntity> insertList = new ArrayList<>();
        List<OpportunityProductEntity> updateList = new ArrayList<>();
        List<OpportunityProductEntity> delList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        // 产品排序
        Integer sort = 0;
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            sort++;
            // 页面传入的产品id
            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long businessProductId = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
            boolean addProductFlag = formDataValidateProductHelp.addProductFlag(businessProductId);
            Double productNum = jsonObject.getDouble(OpportunityProductEnum.NUM.getAttr());
            Double price = jsonObject.getDouble(OpportunityProductEnum.SELLING_PRICE.getAttr());
            price = price != null ? price : 0;
            Double discount = jsonObject.getDouble(OpportunityProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            // 备注
            String memo = jsonObject.getString(OpportunityProductEnum.MEMO.getAttr());
            Long businessUnit = jsonObject.getLong(SelectProductEnum.BUSINESS_UNIT.getAttr());
            JSONObject productData = productMap.get(pageProductId).getData();
            OpportunityProductEntity opportunityProduct;
            if (addProductFlag) {
                opportunityProduct = new OpportunityProductEntity();
                insertList.add(opportunityProduct);
            } else if (originProductMap.containsKey(businessProductId)) {
                opportunityProduct = originProductMap.get(businessProductId);
                opportunityProduct.setDel(DelEnum.NORMAL.getDel());
                updateList.add(opportunityProduct);
                originProductMap.remove(businessProductId);
                productData.put(ProductEnum.PRICE.getAttr(),opportunityProduct.getHistoricalPrice());
            }else if (approveFailedProductMap.containsKey(businessProductId)) {
                opportunityProduct = approveFailedProductMap.get(businessProductId);
                opportunityProduct.setDel(DelEnum.NORMAL.getDel());
                updateList.add(opportunityProduct);
                productData.put(ProductEnum.PRICE.getAttr(),opportunityProduct.getHistoricalPrice());
                originProductMap.remove(businessProductId);
            } else {
                continue;
            }
            opportunityProduct.setCorpid(corpid);
            opportunityProduct.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            opportunityProduct.setOpportunityId(oppId);
            opportunityProduct.setFormId(formId);
            opportunityProduct.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            opportunityProduct.setProductId(pageProductId);
            opportunityProduct.setProductNum(productNum);
            opportunityProduct.setPrice(price);
            opportunityProduct.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            opportunityProduct.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            opportunityProduct.setDiscount(discount);
            opportunityProduct.setCost(productData.getDouble(ProductEnum.COST.getAttr()));
            opportunityProduct.setSort(sort);
            opportunityProduct.setMemo(memo);
            opportunityProduct.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, opportunityProduct);
                opportunityProduct.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                opportunityProduct.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(SelectProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            opportunityProduct.setData(jsonObject);
        }

        if (CollectionUtils.isNotEmpty(insertList)) {
            opportunityProductModel.insertBatch(insertList);
        }

        if (CollectionUtils.isNotEmpty(updateList)) {
            opportunityProductModel.updateMulti(updateList, corpid);
        }
        List<Long> deleteList = new ArrayList<>();
        for (Map.Entry<Long, OpportunityProductEntity> entry : originProductMap.entrySet()) {
            OpportunityProductEntity delProduct = entry.getValue();
            deleteList.add(delProduct.getId());
        }
        if (CollectionUtils.isNotEmpty(deleteList)) {
            opportunityProductModel.deleteBatch(deleteList, corpid, DelEnum.DELETE.getDel());
        }
    }







    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        String corpid = formatExplainDTO.getCorpid();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(attr, SalesOpportunityEnum.PRODUCTS.getAttr())) {
                explainHelp.formatSelectProductExplains(fieldAttrEntity, XbbRefTypeEnum.SALES_OPPORTUNITY, corpid, OperatePageEnum.NEW.getCode(), false);
                CompanyConfigEntity priceConfig = companyConfigModel.getByConfigAlias(CompanyConfigEnum.PRICE_MANAGE.getAlias(), corpid);
                if (priceConfig != null && Objects.equals(priceConfig.getConfigValue(), "1")) {
                    SaasParticularAttributePoJo saasParticularAttributePoJo = new SaasParticularAttributePoJo();
                    saasParticularAttributePoJo.setIsOpenPrice(BasicConstant.ONE);
                    fieldAttrEntity.setSaasParticularAttributePoJo(saasParticularAttributePoJo);
                }
            }
            if(Objects.equals(attr, SalesOpportunityEnum.LINK_COMPETITOR.getAttr()) || Objects.equals(attr, SalesOpportunityEnum.WIN_COMPETITOR.getAttr())){
                // 新建时关联竞争对手和赢单竞品不支持编辑
                fieldAttrEntity.setEditable(0);
            }
        }
    }

    @Override
    public BaseVO focus(FocusDTO focusDTO) throws XbbException {
        Long dataId = focusDTO.getDataIdList().get(0);
        String corpid = focusDTO.getCorpid();
        String userId = focusDTO.getUserId();
        OpportunityEntityExt opportunityEntityExt = opportunityModel.getByKey(dataId,corpid);
        if (opportunityEntityExt == null || opportunityEntityExt.getDel() != 0){
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        OpportunityFocusEntity opportunityFocusEntity = opportunityFocusModel.getByOpportunityId(dataId,userId,corpid);
        if (opportunityFocusEntity == null){
            opportunityFocusEntity = new OpportunityFocusEntity();
            opportunityFocusEntity.setCorpid(corpid);
            opportunityFocusEntity.setOpportunityId(dataId);
            opportunityFocusEntity.setUserId(userId);
            opportunityFocusEntity.setFocus(focusDTO.getFocus());
            opportunityFocusEntity.setAddTime((long) DateUtil.getInt());
            opportunityFocusEntity.setUpdateTime((long) DateUtil.getInt());
        }else {
            boolean isShare;
            try {
                isShare = companyConfigModel.hasBeenEnable(corpid, CompanyConfigEnum.SHARE_FOCUS_OPPORTUNITY.getAlias(), BasicConstant.IS_USE.toString());
            } catch (XbbException e) {
                isShare = Objects.equals(CompanyConfigEnum.SHARE_FOCUS_OPPORTUNITY.getValue(), BasicConstant.IS_USE.toString());
            }
            Integer focus = focusDTO.getFocus();
            if (isShare && focus == 0){
                //重点共享,所有人员取关
                opportunityFocusModel.unFocusBatch(dataId,corpid);
                return new BaseVO();
            }
            opportunityFocusEntity.setFocus(focusDTO.getFocus());
            opportunityFocusEntity.setUpdateTime((long) DateUtil.getInt());
        }
        opportunityFocusModel.save(opportunityFocusEntity);
        return new BaseVO();
    }

    @Override
    public OpportunityUpdateByBusinessRuleVO updateFormDataByBusinessRule(OpportunityUpdateByBusinessRuleDTO update) throws XbbException {
        OpportunityUpdateByBusinessRuleVO opportunityUpdateByBusinessRuleVO = new OpportunityUpdateByBusinessRuleVO();
        try {
            String corpid = update.getCorpid();
            List<PaasFormDataEntityExt> formDataList = update.getFormDataList();
            List<UpdateDataEntity> updateList = ExplainUtil.getUpdateValueByBusinessRule(update.getFormDataList(), corpid, update.getOperations());

            if(!updateList.isEmpty()){
                opportunityModel.updateBatch(updateList, corpid);
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO();
                BeanUtil.copyProperties(update, businessLogDTO);
                businessLogDTO.setFormDataList(formDataList);
                ruleBusinessLogger.writeLog(businessLogDTO, updateList);
            }
        }catch (Exception e){
            LOG.error("opportunityServiceImp.updateFormDataByBusinessRule根据业务规则更新数据出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return opportunityUpdateByBusinessRuleVO;
    }

    @Override
    public void formatProduct4Show(JSONObject dataList, SaasAnalysisDataDTO saasAnalysisDataDTO) throws XbbException {
        if (dataList == null || saasAnalysisDataDTO == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        String corpid = saasAnalysisDataDTO.getCorpid();
        Long oppId = saasAnalysisDataDTO.getDataId();
        List<OpportunityProductEntity> oppProductList = new ArrayList<>();
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        JSONObject productFinalObj = new JSONObject();
        JSONArray productArray = new JSONArray();
        // id为空时需要从产品表查数据拼装oppProductList 是从审批通过那边传送过来的
        if (saasAnalysisDataDTO.getForProcess()) {
            JSONArray productArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(FastJsonHelper.getJsonObjectOrDefaultFromFormData(dataList, SalesOpportunityEnum.PRODUCTS.getAttr(), new JSONObject()), StringConstant.PRODUCT_LIST, new JSONArray());
            List<Long> productIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (int i = 0; i < productArr.size(); i++) {
                JSONObject jsonObject = productArr.getJSONObject(i);
                // 页面传入的产品的id
                Long productId = jsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                productIdIn.add(productId);
            }
            // 获取产品信息
            if (productIdIn.size() >= 1) {
                // 从产品表中获取对应的产品信息
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("idIn", productIdIn);
                params.put("del", 0);
                List<ProductEntityExt> productList = productModel.findEntitys(params);
                if (productList != null) {
                    for (ProductEntityExt entity : productList) {
                        productMap.put(entity.getId(), entity);
                    }
                }
            }
            // 产品排序
            Integer sort = 0;
            for (int i = 0; i < productArr.size(); i++) {
                JSONObject jsonObject = productArr.getJSONObject(i);
                sort++;
                // 页面传入的产品id
                Long pageProductId = FastJsonHelper.getLongOrDefaultFromFormData(jsonObject, StringConstant.SAAS_LINK_BUSINESS_ID, 0L);
                // 获取前端返回的产品成本
                Double cost = StringUtil.toDouble(jsonObject.getString("estimateCost"), 0D);
                // 产品数量
                Double productNum = getDoubleOrDefaultFromFormData(jsonObject, RelativeProductEnum.NUM.getSaasAttr(), 0D);
                // 售价
                Double price = getDoubleOrDefaultFromFormData(jsonObject, RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), 0D);
                // 折扣：默认为100%
                Double discount = getDoubleOrDefaultFromFormData(jsonObject, RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), 0D);
                if (productMap.containsKey(pageProductId)) {
                    ProductEntityExt product = productMap.get(pageProductId);
                    JSONObject productObject = product.getData();
                    String productName = FastJsonHelper.getStringOrDefaultFromFormData(productObject, ProductEnum.NAME.getAttr(), "");
                    String specification = FastJsonHelper.getStringOrDefaultFromFormData(productObject, ProductEnum.SPECIFICATION_LINK_TEXT.getAttr(), "");
                    specification = specificationModel.joinSpecification(specification);
                    String unit = FastJsonHelper.getStringOrDefaultFromFormData(productObject, ProductEnum.UNIT.getAttr(), "");
                    String productNo = FastJsonHelper.getStringOrDefaultFromFormData(productObject, ProductEnum.PRODUCT_NO.getAttr(), "");
                    OpportunityProductEntity opportunityProduct = new OpportunityProductEntity();
                    opportunityProduct.setProductUnit(unit);
                    opportunityProduct.setCorpid(corpid);
                    opportunityProduct.setProductId(pageProductId);
                    opportunityProduct.setProductNum(productNum);
                    opportunityProduct.setProductNo(productNo);
                    opportunityProduct.setPrice(price);
                    opportunityProduct.setProductName(productName);
                    opportunityProduct.setSpecification(specification);
                    opportunityProduct.setDiscount(discount);
                    opportunityProduct.setCost(cost);
                    opportunityProduct.setSort(sort);
                    oppProductList.add(opportunityProduct);
                }
            }
        } else {
            // 获取关联产品
            oppProductList = opportunityProductModel.getProductsByOppId(oppId, corpid);
            if (oppProductList == null || oppProductList.size() == 0) {
                productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
                dataList.put(SalesOpportunityEnum.PRODUCTS.getAttr(), productFinalObj);
                return;
            }
            List<Long> oppIds = new ArrayList<>(oppProductList.size());

            for (OpportunityProductEntity entity : oppProductList) {
                oppIds.add(entity.getProductId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", 0);
            param.put("idIn", oppIds);
            List<ProductEntityExt> productEntityExts = productModel.findEntitys(param);
            if (productEntityExts == null || productEntityExts.size() == 0) {
                productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
                dataList.put(SalesOpportunityEnum.PRODUCTS.getAttr(), productFinalObj);
                return;
            }
            for (ProductEntityExt entityExt : productEntityExts) {
                productMap.put(entityExt.getId(), entityExt);
            }
        }


        // 获取关联产品需要展示的字段
        BusinessProductEnum businessProductEnum = BusinessProductEnum.getByCode(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, FieldAttrEntity> nowOppProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, nowOppProductExplainMap);

        Map<Integer, JSONObject> productObjectMap = new TreeMap<>();
        if (businessProductEnum != BusinessProductEnum.UNKNOW) {
            List<RelativeProductEnum> businessProductEnumList = businessProductEnum.getList();
            for (OpportunityProductEntity entity : oppProductList) {
                JSONArray attrArray = new JSONArray();
                JSONObject productObj = new JSONObject();
                Long productId = entity.getProductId();
                if (productMap.containsKey(productId)) {
                    JSONObject productData = productMap.get(productId).getData();
                    Double price = entity.getPrice();
                    price = price == null ? 0 : price;
                    Double discount = entity.getDiscount();
                    discount = discount == null ? 0 : discount;
                    Double productNum = entity.getProductNum();
                    productNum = productNum == null ? 0 : productNum;
                    for (RelativeProductEnum productEnum : businessProductEnumList) {
                        String saasAttr;
                        FieldAttrEntity fieldAttrEntity = null;
                        if (Objects.equals(productEnum, PRODUCT_PRICE) || Objects.equals(productEnum, SALE_PRODUCT_PRICE) || Objects.equals(productEnum, SUBTOTAL)) {
                            saasAttr = ProductEnum.PRICE.getSaasAttr();
                        } else {
                            saasAttr = productEnum.getSaasAttr();
                        }
                        if (nowProductExplainMap.containsKey(saasAttr)) {
                            fieldAttrEntity = nowProductExplainMap.get(saasAttr);
                        }
                        switch (productEnum) {
                            case NAME:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NAME, entity.getProductName(), fieldAttrEntity));
                                break;
                            case PRODUCT_NO:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(PRODUCT_NO, entity.getProductNo(), fieldAttrEntity));
                                break;
                            case BARCODE:
                                String barcode = productData.getString(ProductEnum.BARCODE.getAttr());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(BARCODE, barcode, fieldAttrEntity));
                                break;
                            case SPECIFICATION:
                                // 格式化规格
                                String specification = specificationModel.joinSpecification(entity.getSpecification());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SPECIFICATION, specification, fieldAttrEntity));
                                break;
                            case PRODUCT_PRICE:
                                Double productPrice = productData.getDouble(ProductEnum.PRICE.getAttr());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(PRODUCT_PRICE, productPrice == null ? 0 : productPrice, fieldAttrEntity));
                                break;
                            case SALE_DISCOUNT:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SALE_DISCOUNT, discount, fieldAttrEntity));
                                break;
                            case SALE_PRODUCT_PRICE:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SALE_PRODUCT_PRICE, price, fieldAttrEntity));
                                break;
                            case NUM:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NUM, productNum, fieldAttrEntity));
                                break;
                            case UNIT:
                                String productUnit = entity.getProductUnit();
                                String unitStr = productModel.getProductUnitTextByValue(productUnit, fieldAttrEntity);
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(UNIT, unitStr, fieldAttrEntity));
                                break;
                            case SUBTOTAL:
                                Double subTotal = price * productNum;
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SUBTOTAL, subTotal, fieldAttrEntity));
                                break;
                            default:
                                break;
                        }
                        productObj.put("result", attrArray);
                        productObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, entity.getProductId());
                        productObj.put(StringConstant.BUSINESS_PRODUCT_ID, entity.getId());
                        productObj.put("parentId", entity.getParentId());
                        productObj.put("estimateCost", entity.getCost());
                    }
                }
                productObjectMap.put(entity.getSort(), productObj);
            }
            // 产品排序
            for (JSONObject jsonObject : productObjectMap.values()) {
                productArray.add(jsonObject);
            }
            productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
            dataList.put(SalesOpportunityEnum.PRODUCTS.getAttr(), productFinalObj);
        }
    }

    @Override
    public PagingProductVO getPagingProduct(PagingProductDTO pagingProductDTO) throws XbbException {
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.OPPORTUNITY_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, opportunityProductModel, pagingProductDTO.getPageSize());
        List<OpportunityProductEntity> opportunityProductList = (List<OpportunityProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, opportunityProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatProduct4DetailShow(opportunityProductList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    public DetailProductVO formatProduct4DetailShow(List<OpportunityProductEntity> opportunityProductList, PagingProductDTO pagingProductDTO) throws XbbException{
        DetailProductVO detailProductVO = new DetailProductVO();
        JSONArray productArray = new JSONArray();
        for (OpportunityProductEntity opportunityProductEntity : opportunityProductList) {
            JSONObject json = new JSONObject();
            if (Objects.nonNull(opportunityProductEntity.getData())) {
                json = opportunityProductEntity.getData();
            }
            if (Objects.nonNull(opportunityProductEntity.getBusinessUnit())) {
                opportunityProductEntity.setProductNum(Arith.div(opportunityProductEntity.getProductNum(), opportunityProductEntity.getRate()));
                opportunityProductEntity.setProductUnit(opportunityProductEntity.getBusinessUnit().toString());
                JSONObject priceData = opportunityProductEntity.getPriceData();
                if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                    opportunityProductEntity.setHistoricalPrice(priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                    opportunityProductEntity.setPrice(priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()));
                }
            }
            for (OpportunityProductEnum opportunityProductEnum : OpportunityProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(opportunityProductEnum.getShowType())) {
                    continue;
                }
                String attr = opportunityProductEnum.getAttr();
                switch (opportunityProductEnum) {
                    case PRODUCT:
                        json.put(attr, opportunityProductEntity.getProductId());
                        break;
                    case PRICE:
                        json.put(attr,opportunityProductEntity.getHistoricalPrice());
                        break;
                    case NUM:
                        json.put(attr, opportunityProductEntity.getProductNum());
                        break;
                    case DISCOUNT:
                        json.put(attr, opportunityProductEntity.getDiscount());
                        break;
                    case SELLING_PRICE:
                        json.put(attr, opportunityProductEntity.getPrice());
                        break;
                    case SELL_TOTAL:
                        if (Objects.nonNull(opportunityProductEntity.getPrice()) && Objects.nonNull(opportunityProductEntity.getProductNum())) {
                            json.put(attr, Arith.mul(opportunityProductEntity.getPrice(), opportunityProductEntity.getProductNum()));
                        }
                        break;
                    case MEMO:
                        json.put(attr, opportunityProductEntity.getMemo());
                        break;
                    case UNIT:
                        json.put(attr, opportunityProductEntity.getProductUnit());
                        break;
                    default:
                        break;
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, opportunityProductEntity.getId());
            json.put(BusinessConstant.PARENT_ID, opportunityProductEntity.getParentId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }

    @Override
    public void formatProduct4Show2(Long dataId, String corpid, JSONObject data, UpdateDataTypeEnum updateDataTypeEnum) throws XbbException {
        opportunityModel.formatProduct4Show2(dataId, corpid, data, updateDataTypeEnum);
    }

    @Override
    public JSONObject formatSingleProduct(OpportunityProductEntity opportunityProductEntity) {
        return opportunityModel.formatSingleProduct(opportunityProductEntity);
    }

    @Override
    public OpportunityDeleteBatchVO deleteBatch(OpportunityDeleteBatchDTO opportunityDeleteBatchDTO) throws XbbException {
        OpportunityDeleteBatchVO opportunityDeleteBatchVO= new OpportunityDeleteBatchVO();
        try {
            List<Long> idIn = opportunityDeleteBatchDTO.getDataIdList();
            String corpid = opportunityDeleteBatchDTO.getCorpid();
            Map<String, Object> param = BeanUtil.convertBean2Map(opportunityDeleteBatchDTO, true);
            param.put("idIn", idIn);
            List<OpportunityEntityExt> opportunityList = opportunityModel.findEntitys(param);
            if (CollectionsUtil.isEmpty(opportunityList)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
            }

            //查询产品名称
            Map<String, String> noAndName= new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            BoolQueryBuilder productBuilder = boolQuery();
            // 添加corpid,formId,del
            productBuilder.filter(termQuery("corpid.keyword", corpid));
            productBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            productBuilder.filter(termsQuery(StringConstant.DATA_ID, idIn));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.SERIALNO.getAlias());
            fieldList.add(SalesOpportunityEnum.getAttrConnectData(SalesOpportunityEnum.NAME));
            List<PaasFormDataEntityExt> opportunityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OPPORTUNITY, productBuilder, PaasFormDataEntityExt.class, fieldList);
            for(PaasFormDataEntityExt opportunity : opportunityExtList){
                JSONObject data = opportunity.getData();
                String no = opportunity.getSerialNo();
                String name = FastJsonHelper.getStringOrDefaultFromFormData(data, SalesOpportunityEnum.NAME.getAttr(), "");
                noAndName.put(no, name);
            }
            // TODO 列表循环校验删除权限
            // 删除机会
            if(!idIn.isEmpty()) {
                if(BasicConstant.ONE.equals(opportunityDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    opportunityModel.deleteByKey(idIn.get(0),corpid);
                }else {
                    opportunityModel.deleteBatch(idIn, corpid);
                }
                marketActivityForStaticHelp.deleteBatchMarketActivity(idIn, XbbRefTypeEnum.SALES_OPPORTUNITY ,corpid, DelEnum.DELETE.getDel());
            }
            // 删除机会团队关系
            OpportunityUserDeleteBatchDTO opportunityUserDeleteBatchDTO = new OpportunityUserDeleteBatchDTO();
            BeanUtil.copyProperties(opportunityDeleteBatchDTO, opportunityUserDeleteBatchDTO);
            opportunityUserDeleteBatchDTO.setOpportunityIdIn(idIn);
            opportunityUserService.deleteBatch(opportunityUserDeleteBatchDTO);
            // 删除机会产品
            opportunityProductModel.deleteBatchByProductId(idIn, corpid);
            PushNotifyDeleteDTO pushNotifyDeleteDTO = new PushNotifyDeleteDTO();
            BeanUtil.copyProperties(opportunityDeleteBatchDTO, pushNotifyDeleteDTO);
            pushNotifyDeleteDTO.setNeedDelNotifyIdList(idIn);
            pushNotifyDeleteDTO.setBusinessType(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
            pushNotifyService.deletePushNotify(pushNotifyDeleteDTO);
            // TODO 删除审批记录
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            if (Objects.equals(1, opportunityDeleteBatchDTO.getIsBusinessRule())) {
                operateTypeEnum = OperateTypeEnum.RULE_DELETE;
            }
            // 删除机会时需要删除竞争对手关系
            competitorAnalysisModel.deleteByOpportunityIds(idIn,corpid);

            //生成删除日志(区分单个删除和批量删除)
            String userId = opportunityDeleteBatchDTO.getUserId();
            String userName = opportunityDeleteBatchDTO.getLoginUserName();
            List<String> list = new ArrayList<>();
            Iterator<String> iterator = noAndName.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String value = noAndName.get(key);
                if(StringUtil.isEmpty(value)){
                    list.add(key);
                } else {
                    StringBuilder sb = new StringBuilder();
                    sb.append(key).append("（").append(value).append("）");
                    list.add(sb.toString());
                }
            }
            String nameStr = StringUtils.join(list, "、");
            Integer singleFlag = opportunityDeleteBatchDTO.getSingleFlag();
            if(Objects.equals(0,singleFlag)||idIn.size() > 1){
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(OperationLogHelp.setDetailTitle());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                DeleteBatchOperationLogDTO deleteBatchOperationLogDTO = new DeleteBatchOperationLogDTO( corpid,  userId,  userName, null,  operateTypeEnum,
                        null,  nameStr,  null,  idIn.size(),opportunityDeleteBatchDTO.getHttpHeader(),opportunityDeleteBatchDTO.getFormId(),opportunityDeleteBatchDTO.getBusinessType());
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                operationLogHandle.deleteBatch(infoArrPojoList,deleteBatchOperationLogDTO);
            } else if (Objects.equals(1,singleFlag)){
                // 防止极端情况nameStr为空，主要来自合并客户
                DeleteOperationLogDTO deleteOperationLogDTO = new DeleteOperationLogDTO(corpid,userId,userName,null,operateTypeEnum,idIn.get(0).toString(),nameStr,null,opportunityDeleteBatchDTO.getHttpHeader(),opportunityDeleteBatchDTO.getFormId(),opportunityDeleteBatchDTO.getBusinessType());
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                operationLogHandle.delete(deleteOperationLogDTO);
            }

            // 删除机会动态
            try {
                if(!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),opportunityDeleteBatchDTO.getDistributorMark())) {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategy(ProjectLogEnum.OPPORTUNITY_DELETE.getSubType());
                    FormDataDeleteBatchDTO formDataDeleteBatchDTO = BeanUtil.copyProperties(opportunityDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                    List<PaasFormDataEntityExt> allowDeletePaasFormDatas = new ArrayList<>(opportunityList.size());
                    BeanUtil.copyPropertiesList(opportunityList, allowDeletePaasFormDatas, PaasFormDataEntityExt.class);
                    dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO,
                            opportunityList.stream().map(OpportunityEntityExt::getId).collect(Collectors.toList()), allowDeletePaasFormDatas));
                }
            } catch (Exception e) {
                LOG.error("删除机会动态失败：", e);
            }

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("opportunityServiceImp.deleteBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return opportunityDeleteBatchVO;
    }

    /**
     * 关联新建时格式化解释
     *
     * @param handlerExplainInLinkItemDTO 入参
     * @throws XbbException 异常
     * @author feng.zheng
     * @date 2019-03-16 20:53
     */
    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContactField = new FieldAttrEntity();
        FieldAttrEntity ownerField = new FieldAttrEntity();
        FieldAttrEntity coUserIdField = new FieldAttrEntity();
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        for(FieldAttrEntity fieldAttrEntity :explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.CUSTOMER_NAME.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.CONTACT_NAME.getAttr())) {
                linkContactField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.OWNER_ID.getAttr())) {
                ownerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.COUSER_ID.getAttr())) {
                coUserIdField = fieldAttrEntity;
            }
        }
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                if (Objects.nonNull(handlerExplainInLinkItemDTO.getClueId())) {
                    // 线索转换过来的需要处理默认值
                    Map<Integer, List<UserTeamEntity>> userMap = userTeamService.getUserTeam(handlerExplainInLinkItemDTO.getClueId(), corpid, XbbRefTypeEnum.CLUE.getCode());
                    if (userMap.containsKey(1)) {
                        List<UserTeamEntity> userTeamEntities = userMap.get(1);
                        ownerField.setDefaultAttr(saasUpdateHelp.setUserDefaultValue(userTeamEntities));
                    }
                    if (userMap.containsKey(0)) {
                        List<UserTeamEntity> userTeamEntities = userMap.get(0);
                        coUserIdField.setDefaultAttr(saasUpdateHelp.setUserDefaultValue(userTeamEntities));
                    }
                }
                break;
            case CONTACT:
                String contactName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, ContactEnum.NAME.getAttr(), "");
                linkContactField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, contactName));
                JSONArray linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, ContactEnum.CUSTOMER_NAME.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                break;
            default:
                break;
        }
    }

    @Override
    public ListAppVO formatOpportunityAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        if (totalCount == null || totalCount == 0) {
            return new ListAppVO();
        }
        List<AppListPojo> appListPojos = new ArrayList<>();
        String userId = formDataListDTO.getUserId();
        String corpid = formDataListDTO.getCorpid();
        Integer subBusinessType = formDataListDTO.getSubBusinessType();

        List<Long> opportunityIdIn = new ArrayList<>(esEntities.size());
        for (PaasFormDataEntityExt opportunityEntity : esEntities) {
            opportunityIdIn.add(opportunityEntity.getDataId());
        }

        boolean isShare;
        try {
            isShare = companyConfigModel.hasBeenEnable(corpid, CompanyConfigEnum.SHARE_FOCUS_OPPORTUNITY.getAlias(), BasicConstant.IS_USE.toString());
        } catch (XbbException e) {
            isShare = Objects.equals(CompanyConfigEnum.SHARE_FOCUS_OPPORTUNITY.getValue(), BasicConstant.IS_USE.toString());
        }
        List<Long> dataIdList;
        if (isShare){
            dataIdList = opportunityFocusModel.getShareOpportunityIdList(corpid);
        }else {
            dataIdList = opportunityFocusModel.getNoShareOpportunityIdList(userId,corpid);
        }
        Map<Long, Integer> focusMap = new HashMap<>(dataIdList.size());
        for (Long opportunityId : dataIdList) {
            focusMap.put(opportunityId, 1);
        }

        //有提醒的机会
        List<Long> pushNotifyList = new ArrayList<>();
        saasListHelp.getPushNotify(opportunityIdIn, corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), pushNotifyList);


        // 协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        userTeamService.getUserIdMap(opportunityIdIn,corpid,formDataListDTO.getBusinessType(),false ,mainUserMap,coUserMap);
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        BeanUtil.copyProperties(formDataListDTO, handlerExplainDTO);

        for (PaasFormDataEntityExt opportunityEntity : esEntities) {
            long id = opportunityEntity.getDataId();
            long appId = opportunityEntity.getAppId();
            long menuId = opportunityEntity.getMenuId();
            long formId = opportunityEntity.getFormId();
            JSONObject data = opportunityEntity.getData();

            JSONObject superScript = new JSONObject();
            JSONObject others = new JSONObject();
            // 角标
            if(!Objects.equals(subBusinessType, XbbRefTypeEnum.CUSTOMER_FOCUS.getCode())){
                if (null != focusMap.get(id)) {
                    superScript.put("focus", 1);
                }
            }
            superScript.put("message",pushNotifyList.contains(id) ? 1 : 0);
            // isAchived 为1代表归档，2代表未归档
            JSONObject tagData = opportunityEntity.getTagData();
            if(Objects.equals(tagData.getInteger("isAchived"), 1)){
                superScript.put("archived", 1);
            }
            /*-- 其他 -*/
            //格式化钱币
            String estimateAmount = FastJsonHelper.getStringOrDefaultFromFormData(data, SalesOpportunityEnum.ESTIMATE_AMOUNT.getAttr(), "0");
            others.put("amount", estimateAmount);

            // 当前数据的创建人、负责人、协同人、当前操作人
            handlerExplainDTO.setOwnerId(mainUserMap.get(id));
            handlerExplainDTO.setCoUserId(coUserMap.get(id));
            handlerExplainDTO.setCreatorId(opportunityEntity.getCreatorId());
            // 机会阶段是否开启
            // 由于机会多模板，该入口无法区分不同模板，顾注释，若上线后用户反映激烈，增加列表页入参，替换字段类型
//            boolean stageOpen = commonHelp.ifStageOpen(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), formDataListDTO.getExplainMap(), handlerExplainDTO);
//            if (stageOpen) {
//                String staleStage = FastJsonHelper.getStringOrDefaultFromFormData(data, SalesOpportunityEnum.SALE_STAGE.getAttr(), "");
//                others.put("salesStage", staleStage);
//            }


            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);

            summaryList.forEach(item -> {
                if (Objects.equals(item.getAttr(), SalesOpportunityEnum.ESTIMATE_END_TIME.getAttr())) {
                    if (item.getValue() != null && !item.getValue().isEmpty()) {
                        String estimateTime = (String) item.getValue().get(0);
                        Long estimateEndTime = DateTimeUtil.getInt(estimateTime, DateTimeUtil.SDFDate);
                        if (estimateEndTime < DateTimeUtil.getTodayInt()) {
                            String nameOrCode = data.getString(SalesOpportunityEnum.SALE_STAGE.getAttr());
                            List<Integer> noRemindCode = Arrays.asList(StageTypeEnum.SUCCESS_STAGE.getType(),StageTypeEnum.FAIL_STAGE.getType(),StageTypeEnum.CANCEL_STAGE.getType());
                            SaleStageEntity saleStage = null;
                            if (StringUtil.isNotEmpty(nameOrCode)) {
                                saleStage = saleStageModel.getByCode(corpid, formDataListDTO.getFormId(), nameOrCode);
                            }
                            if(Objects.isNull(saleStage) || !noRemindCode.contains(saleStage.getType())) {
                                // 预计结束时间延期标红
                                item.setStatus("delay");
                            }
                        }
                    }
                }
            });
            //app系统关联数据展示需要 others 和 superScript
            data.put("others",others);
            data.put("superScript",superScript);

            appListPojos.add(new AppListPojo(id, titleList, summaryList, superScript, lablesList, others, appId, menuId, formId));
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return  listAppVO;
    }

    @Override
    public OpportunityUpdateBatchVO updateBatch(OpportunityUpdateBatchDTO opportunityUpdateBatchDTO) throws XbbException {
        OpportunityUpdateBatchVO opportunityUpdateBatchVO = new OpportunityUpdateBatchVO();
        try {
            String corpid = opportunityUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<OpportunityUpdateDTO> opportunityList = opportunityUpdateBatchDTO.getOpportunityList();
            if (Objects.nonNull(opportunityList) && !opportunityList.isEmpty()) {
                opportunityList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                opportunityModel.updateBatch(updateList, corpid);
            }
            dealStaticMarket(corpid, opportunityList);
        } catch (Exception e) {
            LOG.error("opportunityServiceImpl.updateBatch 报错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return opportunityUpdateBatchVO;
    }

    @Override
    public void updateBatch4Script(OpportunityUpdateBatchDTO opportunityUpdateBatchDTO, boolean async) throws XbbException {
        try {
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<OpportunityUpdateDTO> opportunityList = opportunityUpdateBatchDTO.getOpportunityList();
            if (CollectionsUtil.isNotEmpty(opportunityList)) {
                opportunityList.forEach(item -> updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), item.getCorpid(), item.getUpdateTime())));
            }
            if (CollectionsUtil.isNotEmpty(updateList)) {
                opportunityModel.updateBatch4Script(updateList, async);
            }
        } catch (Exception e) {
            LOG.error("opportunityServiceImpl.updateBatch4Script 报错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void updateBatch4Sync(OpportunityUpdateBatchDTO opportunityUpdateBatchDTO) throws XbbException {
        try {
            String corpid = opportunityUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<OpportunityUpdateDTO> opportunityList = opportunityUpdateBatchDTO.getOpportunityList();
            if (CollectionsUtil.isNotEmpty(opportunityList)) {
                opportunityList.forEach(item -> updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid, null)));
            }
            if (CollectionsUtil.isNotEmpty(updateList)) {
                opportunityModel.updateBatch4Sync(updateList, corpid);
            }
        } catch (Exception e) {
            LOG.error("opportunityServiceImpl.updateBatch4Sync 报错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void batchEditAttr(OpportunityEditAttrUpdateDTO opportunityEditAttrUpdateDTO) throws XbbException {
        String userId = opportunityEditAttrUpdateDTO.getUserId();
        String loginUserName = opportunityEditAttrUpdateDTO.getLoginUserName();
        // 标签特殊处理
        Integer isBatch = opportunityEditAttrUpdateDTO.getIsBatch();
        Integer businessType = opportunityEditAttrUpdateDTO.getBusinessType();
        Boolean isFieldDependence = opportunityEditAttrUpdateDTO.getIsFieldDependence();
        try {
            List<Long> idIn = opportunityEditAttrUpdateDTO.getDataIdList();
            Map<String, Object> param = BeanUtil.convertBean2Map(opportunityEditAttrUpdateDTO, true);
            param.put("idIn", idIn);
            List<OpportunityEntityExt> opportunityList = opportunityModel.findEntitys(param);
            if (Objects.isNull(opportunityList)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            List<OpportunityUpdateDTO> opportunityUpdateList = new ArrayList<>();
            String corpid = opportunityEditAttrUpdateDTO.getCorpid();
            Long formId = opportunityEditAttrUpdateDTO.getFormId();

            AttrValuePojo singleAttrValuePojo = ProSaveHelp.getSingleAttrValuePojo(isFieldDependence, opportunityEditAttrUpdateDTO.getFieldEditedList());
            if (SalesOpportunityEnum.SALE_STAGE.getAttr().equals(singleAttrValuePojo.getAttr())) {
//                Integer code = (Integer) opportunityEditAttrUpdateDTO.getValue();
                // 销售阶段不允许快编
//                // TODO 非老板且非管理员不能修改归档状态
//                String userId = opportunityEditAttrUpdateDTO.getUserId();
//                SaleStageEntity saleStage = saleStageModel.getByCode(corpid, formId, code);
//                if (Objects.isNull(saleStage)) {
//                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
//                }
//                UserVO userVO = opportunityEditAttrUpdateDTO.getLoginUser();
//                String salesStageName = saleStage.getName();
//                String loginUserName = opportunityEditAttrUpdateDTO.getLoginUserName();
//                List<CustomerCommunicateInsertDTO> customerCommunicateList = new ArrayList<>();
//                List<SaleStageEntity> saleStageList = getSalesStageList(corpid, true);
//                Map<Long, OpportunityNextStageVO> opportunityNextStageMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//                for (OpportunityEntityExt item : opportunityList) {
//                    JSONObject data = item.getData();
//                    if (Objects.isNull(data)) {
//                        continue;
//                    }
//                    if (Objects.nonNull(data)
//                            && Objects.nonNull(data.getInteger(SalesOpportunityEnum.IS_ARCHIVED.getAttr()))
//                            && data.getInteger(SalesOpportunityEnum.IS_ARCHIVED.getAttr()) == 1){
//                        continue;
//                    }
//                    OpportunityUpdateDTO opportunityUpdateDTO = new OpportunityUpdateDTO();
//                    opportunityUpdateDTO.setId(item.getId());
//                    JSONObject updateData = new JSONObject();
//                    updateData.put(SalesOpportunityEnum.SALE_STAGE.getAttr(), code);
//                    // TODO 预计盈率
//                    if (SaleStageTypeEnum.LOSE.getType().equals(saleStage.getType())
//                            || SaleStageTypeEnum.CANCEL.getType().equals(saleStage.getType())) {
//                        updateData.put(SalesOpportunityEnum.IS_ARCHIVED.getAttr(), 1);
//                    }
//                    long now = DateUtil.getInt();
//                    updateData.put(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr(), now);
//                    opportunityUpdateDTO.setData(updateData);
//                    opportunityUpdateList.add(opportunityUpdateDTO);
//                    CustomerCommunicateInsertDTO customerCommunicateInsertDTO = new CustomerCommunicateInsertDTO();
//                    customerCommunicateInsertDTO.setAddTime(now);
//                    customerCommunicateInsertDTO.setUpdateTime(now);
//                    JSONObject customerCommunicateData = new JSONObject();
//                    customerCommunicateData.put(CustomerCommunicateEnum.USER_ID.getAttr(), userId);
//                    customerCommunicateData.put(CustomerCommunicateEnum.USER_NAME.getAttr(), userVO.getName());
//                    customerCommunicateData.put(CustomerCommunicateEnum.USER_AVATAR.getAttr(), Collections.singletonList(userVO.getAvatar()));
//                    Long customerId = data.getLong(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
//                    if (Objects.nonNull(customerId)) {
//                        customerCommunicateData.put(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr(), customerId);
//                    }
//                    String customerName = data.getString(CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
//                    if (Objects.nonNull(data.getLong(CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr()))) {
//                        customerCommunicateData.put(CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), customerName);
//                    }
////                    customerCommunicateData.put(CustomerCommunicateEnum.TYPE.getAttr(), CommunicateTypeEnum.PROJECT_LOG.getCode());
//                    String content = "“" + loginUserName + "”将机会的销售阶段更改为“" + salesStageName + "”";
//                    customerCommunicateData.put(CustomerCommunicateEnum.MEMO.getAttr(), content);
//                    customerCommunicateData.put(CustomerCommunicateEnum.COMMUNICATE_TIME.getAttr(), now);
//                    customerCommunicateData.put(CustomerCommunicateEnum.AUTO_GEN.getAttr(), 1);
////                    customerCommunicateData.put(CustomerCommunicateEnum.CONTRACT_ID.getAttr(), 0);
//                    customerCommunicateInsertDTO.setData(customerCommunicateData);
//                    customerCommunicateList.add(customerCommunicateInsertDTO);
//
//                    // TODO 处理阶段记录
//                    if (Objects.nonNull(data.getInteger(SalesOpportunityEnum.SALE_STAGE.getAttr()))){
//                        Integer saleStageId = data.getInteger(SalesOpportunityEnum.SALE_STAGE.getAttr());
//                        OpportunityNextStageVO opportunityNextStageVO = judgeStage(saleStageList, saleStageId, code);
//                        opportunityNextStageMap.put(item.getId(), opportunityNextStageVO);
//                    }
//                }
//
//                if (!opportunityNextStageMap.isEmpty()) {
//                    resolveStage(opportunityEditAttrUpdateDTO, opportunityNextStageMap);
//                }
//                if (!customerCommunicateList.isEmpty()) {
//                    CustomerCommunicateInsertBatchDTO customerCommunicateInsertBatchDTO = new CustomerCommunicateInsertBatchDTO();
//                    BeanUtil.copyProperties(opportunityEditAttrUpdateDTO, customerCommunicateInsertBatchDTO);
//                    customerCommunicateInsertBatchDTO.setCustomerCommunicateList(customerCommunicateList);
//                    customerCommunicateService.insertBatch(customerCommunicateInsertBatchDTO);
//                }
            } else {
                idIn.forEach((item) -> {
                    OpportunityUpdateDTO opportunityUpdateDTO = new OpportunityUpdateDTO();
                    opportunityUpdateDTO.setId(item);
                    JSONObject data = ProSaveHelp.getBatchUpdateData(opportunityEditAttrUpdateDTO.getFieldEditedList());
                    opportunityUpdateDTO.setData(data);
                    try {
                        if (Objects.nonNull(data) && data.containsKey(FieldTypeEnum.DEPARTMENTID.getAlias())) {
                            JSONObject jsonObject = data.getJSONObject(FieldTypeEnum.DEPARTMENTID.getAlias());
                            Long id = jsonObject.getLong("id");
                            opportunityUpdateDTO.setDepartmentId(id);
                        }
                    } catch (Exception exception) {
                    }
                    opportunityUpdateList.add(opportunityUpdateDTO);
                });
            }
            //权限团队校验前置了
            List<Long> errorIdList = new ArrayList<>();
//            List<Long> errorIdList = userTeamHelp.batchTeamMembersCheckEditPermission(opportunityEditAttrUpdateDTO.getBusinessType(), opportunityEditAttrUpdateDTO.getSaasMark(),
//                    opportunityEditAttrUpdateDTO.getMenuId(), opportunityEditAttrUpdateDTO.getLoginUser(), opportunityEditAttrUpdateDTO.getDistributorMark(),
//                    opportunityEditAttrUpdateDTO.getDataIdList(), new HashMap<>());
            List<String> errorNameList = new ArrayList<>();
            for (OpportunityEntityExt opportunityEntityExt : opportunityList) {
                if (errorIdList.contains(opportunityEntityExt.getDataId())) {
                    errorNameList.add(opportunityEntityExt.getData().getString(SalesOpportunityEnum.NAME.getAttr()));
                }
            }
            String nameStr = org.apache.commons.lang.StringUtils.join(errorNameList, "、");
            if (CollectionUtils.isNotEmpty(errorNameList)) {
                throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271038.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271038.getMsg(), nameStr));
            }
            if (!opportunityUpdateList.isEmpty()) {
                OpportunityUpdateBatchDTO opportunityUpdateBatchDTO = new OpportunityUpdateBatchDTO();
                BeanUtil.copyProperties(opportunityEditAttrUpdateDTO, opportunityUpdateBatchDTO);
                opportunityUpdateBatchDTO.setOpportunityList(opportunityUpdateList);
                updateBatch(opportunityUpdateBatchDTO);
            }

            // 批量编辑日志
            List<String> updataItemList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (OpportunityEntityExt item : opportunityList) {
                dataIdList.add(item.getId());
            }
            if(Objects.nonNull(isBatch)){
                List<OpportunityEntityExt> newList = opportunityModel.findEntitys(param);
                List<PaasFormDataEntity> newDataList = new ArrayList<>();
                List<PaasFormDataEntity> oldDataList = new ArrayList<>();
                BeanUtil.copyPropertiesList(opportunityList,oldDataList,PaasFormDataEntity.class);
                BeanUtil.copyPropertiesList(newList,newDataList,PaasFormDataEntity.class);
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(opportunityEditAttrUpdateDTO.getSaasMark(),opportunityEditAttrUpdateDTO.getBusinessType());
                UpdateBatchOperationLogDTO updateBatchOperationLogDTO = new UpdateBatchOperationLogDTO(corpid, userId, loginUserName, dataIdList.size(), opportunityEditAttrUpdateDTO.getHttpHeader(),
                        opportunityEditAttrUpdateDTO.getLogFieldEditedList(), newDataList, oldDataList, formId, businessType, isBatch);
                operationLogHandle.updateBatch(updateBatchOperationLogDTO);
            }
        }catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("opportunityServiceImpl.batchEditAttr 报错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }


/*    @Override
    public BusinessProductListVO getOpportunityProductList(BusinessProductListDTO businessProductListDTO, Object object) throws XbbException {
        BusinessProductListVO businessProductListVO = new BusinessProductListVO();

        String corpid = businessProductListDTO.getCorpid();
        String userId = businessProductListDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        Boolean detailGet = businessProductListDTO.getDetailGet();
        Long opportunityId = businessProductListDTO.getDataId();

        // 获取关联产品
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("opportunityId", opportunityId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  businessProductListDTO.getPage());
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, opportunityProductModel, businessProductListDTO.getPageSize());
        List<OpportunityProductEntity> opportunityProducts = (List<OpportunityProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, opportunityProductModel);
        Map<Long, OpportunityProductEntity> opportunityProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> productIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productIds.add(-1L);
        opportunityProducts.forEach(item -> {
            opportunityProductMap.put(item.getProductId(), item);
            productIds.add(item.getProductId());
        });

        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        saasAddHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, null);


        // 根据productIdIn获取对应产品信息，需要分页信息，从es中获取
//        EsDataDTO esDataDTO = new EsDataDTO();
//        esDataDTO.setCorpid(corpid);
//        esDataDTO.setBusinessType(XbbRefTypeEnum.PRODUCT.getCode());
//        esDataDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
//        esDataDTO.setFieldList(null);
//        esDataDTO.setDel(0);
//        List<ConditionsEntityExt> conditionsEntityExtList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        // idIn
//        List<Object> idIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        idIn.addAll(productIds);
//        ConditionsEntityExt flowStatusConditionsEntityExt = new ConditionsEntityExt();
//        flowStatusConditionsEntityExt.setAttr(StringConstant.DATA_ID);
//        flowStatusConditionsEntityExt.setSymbol(ConditionEnum.IN.getSymbol());
//        flowStatusConditionsEntityExt.setValue(idIn);
//        flowStatusConditionsEntityExt.setFieldType(FieldTypeEnum.DATAID.getType());
//        conditionsEntityExtList.add(flowStatusConditionsEntityExt);
//        esDataDTO.setConditionsEntityExtList(conditionsEntityExtList);
//        PaasFormDataEsListVO esDataList = paasFormDataService.getEsDataList(esDataDTO);
//        List<PaasFormDataEntityExt> paasFormDataESList = esDataList.getPaasFormDataESList();
        List<PaasFormDataEntityExt> paasFormDataESList = productService.getProductListById(productIds,corpid, null);

        Map<String, FieldAttrEntity> explainMap = paasFormExplainService.getFieldAttrMapByBusinessType(businessProductListDTO.getBusinessType(), corpid);

        // 返回给前端的接受对象
        JSONObject productFinalObj = new JSONObject();
        JSONArray productArray = new JSONArray();
        Map<Integer, JSONObject> productSortMap = new TreeMap<>();
        // 与productList同级，返回对应关联产品的attr
        String attrStr = "";

        // 总价格
        double totalPrice = 0D;
        // 获取该公司设置的“数字”小数精度
//        Integer numberPrecision = companyConfigService.getNumberPrecision(corpid);
        // 得到该公司设置的金额小数精度
//        Integer amountPrecision = companyConfigService.getAmountPrecision(corpid);
        FieldAttrEntity amountFieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity numFieldAttrEntity = new FieldAttrEntity();
        if(nowProductExplainMap.containsKey(ProductEnum.PRICE.getSaasAttr())) {
            amountFieldAttrEntity = nowProductExplainMap.get(ProductEnum.PRICE.getSaasAttr());
        }
        if(nowProductExplainMap.containsKey(ProductEnum.STOCK.getSaasAttr())) {
            numFieldAttrEntity = nowProductExplainMap.get(ProductEnum.STOCK.getSaasAttr());
        }
        Integer amountPrecision = amountFieldAttrEntity.getAccuracy();
        Integer numberPrecision = numFieldAttrEntity.getAccuracy();

        for (PaasFormDataEntityExt product : paasFormDataESList) {
            Long parentProductId = product.getDataId();
            OpportunityProductEntity opportunityProduct = opportunityProductMap.get(parentProductId);
            if (opportunityProduct == null) {
                continue;
            }
            JSONObject productData = product.getData();
            String specification = FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.SPECIFICATION_LINK_TEXT.getAttr(), "");

            // 价格
            Double productPrice = saasUpdateHelp.getDoubleOrDefaultFromFormData(productData, ProductEnum.PRICE.getAttr(), 0D);
            Double productNum = attrDecimalPrecisionHelper.setPrecision(opportunityProduct.getProductNum(), numberPrecision);
            productPrice = attrDecimalPrecisionHelper.setPrecision(productPrice, amountPrecision);
            Double salesProductPrice = opportunityProduct.getPrice() == null ? 0 : opportunityProduct.getPrice();

            double subTotal = salesProductPrice * productNum;
            // 小计
            totalPrice = Arith.add(totalPrice, subTotal);
            // 折扣
            Double salesDiscount = opportunityProduct.getDiscount() == null ? 100 : opportunityProduct.getDiscount();

            // 17855 【产品】修改产品单价，不应该同步修改系统已有销售机会的产品单价
            try {
                if (opportunityProduct.getDiscount() != null && Double.compare(opportunityProduct.getDiscount(), 0) != 0) {
                    productPrice = salesProductPrice * 100 / opportunityProduct.getDiscount();
                    productPrice = attrDecimalPrecisionHelper.setPrecision(productPrice, amountPrecision);
                }
            } catch (Exception e) {
                LOG.info(e.getMessage());
            }

            FormatRelativeProductEntityExt formatProduct = new FormatRelativeProductEntityExt();
            formatProduct.setProductName(FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.NAME.getAttr(), ""));
            formatProduct.setProductNo(FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.PRODUCT_NO.getAttr(), ""));
            formatProduct.setProductSpecification(specification);
            formatProduct.setProductUnit(FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.UNIT.getAttr(), ""));
            formatProduct.setBarcode(FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.BARCODE.getAttr(), ""));
            formatProduct.setProductNum(productNum);
            formatProduct.setProductPrice(productPrice);
            formatProduct.setSubTotal(subTotal);
            formatProduct.setSaleDiscount(salesDiscount);
            formatProduct.setSaleProductPrice(salesProductPrice);
            String imageUrl = "";
            JSONArray jsonArray = productData.getJSONArray(ProductEnum.PRODUCT_IMGS.getAttr());
            if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()){
                imageUrl = jsonArray.getString(jsonArray.size()-1);
            }
            formatProduct.setImageUrl(imageUrl);
            FormatRelativeProductDTO formatRelativeProductDTO = new FormatRelativeProductDTO();
            BeanUtil.copyProperties(businessProductListDTO, formatRelativeProductDTO);
            formatRelativeProductDTO.setBusinessType(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
            formatRelativeProductDTO.setTargetBusinessType(businessProductListDTO.getBusinessType());
            formatRelativeProductDTO.setCorpid(corpid);
            formatRelativeProductDTO.setNowProductExplainMap(nowProductExplainMap);
            formatRelativeProductDTO.setFormatRelativeProductEntityExt(formatProduct);
            formatRelativeProductDTO.setUserEntity(userEntity);
            JSONObject productObj = productService.getFormatProductJsonArray(formatRelativeProductDTO);
            productSortMap.put(opportunityProduct.getSort(), productObj);
        }

        // 产品排序
        productArray.addAll(productSortMap.values());
        productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
        if (detailGet) {
            productFinalObj.put(BusinessConstant.EXPLAINS, saasGetHelp.getSelectProductExplains(XbbRefTypeEnum.SALES_OPPORTUNITY, businessProductListDTO.getBusinessType(), corpid, PurchaseEnum.PRODUCT.getAttr()));
        }
        productFinalObj.put(StringConstant.REDUNDANT_FIELD_ATTR_BEGIN_FLAG, attrStr);
        businessProductListVO.setProduct(productFinalObj);
//        businessProductListVO.setPageHelper(esDataList.getPageHelper());

        // 产品价格总计
        JSONObject othersObj = new JSONObject();
        String totalMoney = attrDecimalPrecisionHelper.formatMoneyPrecision(totalPrice, explainMap, ContractEnum.AMOUNT.getAttr());
        othersObj.put(BusinessConstant.TOTAL_PRODUCT_MONEY, totalMoney);
        businessProductListVO.setOthers(othersObj);
        businessProductListVO.setPageHelper(pageHelper);
        return businessProductListVO;
    }*/

    /**
     * 插入数据
     * @param formId 表单id
     * @param opportunityId 机会id
     * @param salesStageId
     * @return
     */
    private OpportunityStageLogInsertDTO insert(Long formId, Long opportunityId, Integer salesStageId) {
        OpportunityStageLogInsertDTO opportunityStageLogInsertDTO = new OpportunityStageLogInsertDTO();
        opportunityStageLogInsertDTO.setFormId(formId);
        opportunityStageLogInsertDTO.setOpportunityId(opportunityId);
        opportunityStageLogInsertDTO.setStageCode(salesStageId);
        // 新插入的，是当前阶段
        opportunityStageLogInsertDTO.setIsNow(1);
        long now = DateUtil.getInt();
        opportunityStageLogInsertDTO.setIntoTime(now);
        opportunityStageLogInsertDTO.setOutTime(0L);
        return opportunityStageLogInsertDTO;
    }

    /**
     * 判断是向前更改阶段，还是向后更改阶段，或者是刚插入阶段
     * 如果是向前更改阶段，则获取到该阶段后面的所有阶段id--用于把记录里面该阶段后面的阶段记录的del都置为1
     *
     * @param salesStageList
     * @param oldStageId 更改前所处的阶段id
     * @param newStageId 更改为的阶段id
     * @return 返回map
     * 			flag -1没有更改阶段 ， 0 新插入（新建机会）， 1 向后更改阶段， 2 向前更改阶段
     * 			nextStageIdList 只有flag=2时，才有值：newStageId后面的阶段id
     * @author cp.zhang
     * @time 2016-12-28 下午2:00:48
     */
    public OpportunityNextStageVO judgeStage(List<SaleStageEntity> salesStageList, Integer oldStageId, Integer newStageId) {
        OpportunityNextStageVO opportunityNextStageVO = new OpportunityNextStageVO();
        if (oldStageId == null || oldStageId == 0) {
            //新插入阶段，不是更改阶段
            opportunityNextStageVO.setFlag(0);
            return opportunityNextStageVO;
        }
        if (oldStageId.equals(newStageId)) {
            opportunityNextStageVO.setFlag(-1);
            return opportunityNextStageVO;
        }

        Map<String, Integer> codeSortMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Long> codeIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(SaleStageEntity salesStageEntity : salesStageList) {
            codeIdMap.put(salesStageEntity.getCode(), salesStageEntity.getId());
            codeSortMap.put(salesStageEntity.getCode(), salesStageEntity.getSort());
        }

        Long oldId = codeIdMap.get(oldStageId);
        Integer oldSort = codeSortMap.get(oldStageId);
        Integer newSort = codeSortMap.get(newStageId);
        Long newId = codeIdMap.get(newStageId);

        int flag = 0;
        //sort越大越靠前
        if (oldSort > newSort) {
            //向后更改阶段
            flag = 1;
        }else if (oldSort < newSort) {
            //向前更改阶段
            flag = 2;
        }else if (oldSort.equals(newSort)) {
            //sort相等时，id越大的越靠后
            flag = (oldId < newId)? 1 : 2;
        }
        opportunityNextStageVO.setFlag(flag);

        //处理向前更改阶段的情况
        if (flag == 2) {
            //向前更改阶段，需获取到阶段后面的id
            List<String> nextStageIdList = new ArrayList<>();
            Integer sort = codeSortMap.get(newStageId);

            for(SaleStageEntity salesStageEntity : salesStageList) {
                Boolean result = salesStageEntity.getSort() < sort || (salesStageEntity.getSort().equals(sort) && salesStageEntity.getId() > codeIdMap.get(newStageId));
                if (result) {
                    nextStageIdList.add(salesStageEntity.getCode());
                }
            }
            opportunityNextStageVO.setNextStageIdList(nextStageIdList);
        }

        return opportunityNextStageVO;
    }

    /**
     * 把客户的跟进人同步到新的销售机会
     *
     * @param customerId 客户id
     * @param corpid 公司id
     * @param opportunityId 机会id
     * @throws XbbException 业务异常
     * @author long.rao
     * @date 2019-01-30 15:20
     */
    private void setOpportunityUser(Long customerId, String corpid, Long opportunityId) throws XbbException{
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("customerId", customerId);
        param.put("corpid", corpid);
//        param.put("isMain", 1);
        param.put("del", 0);
        param.put("orderByStr", "is_main desc");
        List<CustomerUserEntity> customerUserList = customerUserModel.findEntitys(param);
        List<String> userIdIn = new ArrayList<>();
        userIdIn.add("-1");
        for(CustomerUserEntity customerUser : customerUserList){
            userIdIn.add(customerUser.getUserId());
        }

        param.clear();
        param.put("userIdIn", userIdIn);
        param.put("corpid", corpid);
        param.put("del", 0);
        List<UserEntity> userList = userModel.findEntitys(param);

        Map<String, UserEntity> userMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(UserEntity user : userList){
            userMap.put(user.getUserId(), user);
        }

        List<UserEntity> validUserList = new ArrayList<>();
        for(CustomerUserEntity customerUser : customerUserList){
            if(userMap.containsKey(customerUser.getUserId())){
                UserEntity userEntity = (UserEntity) CloneUtil.deepClone(userMap.get(customerUser.getUserId()));
                userEntity.setIsMain(customerUser.getIsMain());
                validUserList.add(userEntity);
            }
        }
        for (UserEntity customerUserEntity : validUserList) {
            opportunityUserModel.opportunityUserInsert(customerUserEntity, opportunityId, customerUserEntity.getIsMain());
        }
    }

    @Override
    public void formatExportValue(List<PaasFormDataEntityExt> paasFormDataESList, FormDataListDTO formDataListDTO, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException{
        // 产品
        FieldAttrEntityForImport productFieldAttr = null;
        for (FieldAttrEntityForImport item : fieldAttrList) {
            if (Objects.equals(item.getAttr(), SalesOpportunityEnum.PRODUCTS.getAttr())) {
                productFieldAttr = item;
                break;
            }
        }
        if (Objects.isNull(productFieldAttr)) {
            return;
        }
        List<Long> businessIdIn = new ArrayList<>();
        paasFormDataESList.forEach(paasFormDataEntityExt -> businessIdIn.add(paasFormDataEntityExt.getId()));
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, formDataListDTO.getCorpid());
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put("opportunityIdIn", businessIdIn);
        param.put("orderByStr","sort");
        String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
        List<OpportunityProductEntity> opportunityProductEntityList = opportunityProductModel.findEntitys(param);

        Map<Long, List<OpportunityProductEntity>> opportunityProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> productIdIn = new ArrayList<>();
        opportunityProductEntityList.forEach(opportunityProductEntity -> {
            List<OpportunityProductEntity> productEntityList = new ArrayList<>();
            if (opportunityProductMap.containsKey(opportunityProductEntity.getOpportunityId())) {
                productEntityList.addAll(opportunityProductMap.get(opportunityProductEntity.getOpportunityId()));
            }
            productEntityList.add(opportunityProductEntity);
            opportunityProductMap.put(opportunityProductEntity.getOpportunityId(), productEntityList);
            productIdIn.add(opportunityProductEntity.getProductId());
        });
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + keyword, formDataListDTO.getCorpid()));
        boolQueryBuilder.filter(termsQuery(StringConstant.SAAS_LINK_BUSINESS_ID, productIdIn));
        List<ProductEntityExt> productList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT, boolQueryBuilder, ProductEntityExt.class, null);
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productList.forEach(item -> productMap.put(item.getId(), item));

        Map<String, MultiUnitItemPoJo> groupBaseUnitStringMap = relativeProductHelp.getGroupBaseUnitStringMap(formDataListDTO.getCorpid());

        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataESList) {
            JSONObject formDataObj = paasFormDataEntityExt.getData();
            formDataObj.put(SalesOpportunityEnum.GROSS_PROFIT_RATE.getAttr(), commonHelp.getPercentFormat(saasUpdateHelp.getDoubleIgnoreExceptionFormData(formDataObj, SalesOpportunityEnum.GROSS_PROFIT_RATE.getAttr(), 0D), 3, 2));
            String productAttr = productFieldAttr.getAttr();
            List<OpportunityProductEntity> singleOpportunityProductEntityList = opportunityProductMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>());
            if (singleOpportunityProductEntityList.isEmpty()) {
                formDataObj.put(productAttr, new JSONArray());
                continue;
            }
            JSONArray productArray = new JSONArray();
            for (OpportunityProductEntity entity : singleOpportunityProductEntityList) {
                if (Objects.nonNull(entity.getPriceData()) && entity.getPriceData().size() > 0){
                    entity.getData().putAll(entity.getPriceData());
                }
                JSONObject productItemObj = new JSONObject();
                productItemObj.put(OpportunityProductEnum.DISCOUNT.getAttr(), entity.getDiscount());
                productItemObj.put(OpportunityProductEnum.NUM.getAttr(), entity.getProductNum());
                if (Objects.nonNull(entity.getData())) {
                    productItemObj.putAll(entity.getData());
                }
                Long productId = entity.getProductId();
                ProductEntityExt productEntityExt = productMap.getOrDefault(productId, new ProductEntityExt());
                JSONObject productData = productEntityExt.getData();
                productItemObj.put(SelectProductEnum.PRODUCT_NAME.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.NAME.getAttr(), ""));
                productItemObj.put(SelectProductEnum.PRODUCT_NO.getAttr(), entity.getProductNo());
                productItemObj.put(SelectProductEnum.BARCODE.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.BARCODE.getAttr(), ""));
                productItemObj.put(SelectProductEnum.SPECIFICATION.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(productData, ProductEnum.SPECIFICATION_LINK_TEXT.getAttr(), ""));
                // fix: 44565 【成功部】南京聚铭网络科技有限公司 点销售机会导出失败,空指针判断
                if (Objects.nonNull(productData)) {
                    productItemObj.put(SelectProductEnum.UNIT.getAttr(), productData.get(ProductEnum.UNIT.getAttr()));
                    productItemObj.put(ProductEnum.ENABLE_MULTI_UNIT.getAttr(), productData.getIntValue(ProductEnum.ENABLE_MULTI_UNIT.getAttr()));
                }
                // TODO 精度
                if (Objects.nonNull(entity.getPriceData()) && entity.getPriceData().size() > BasicConstant.ZERO){
                    productItemObj.put(OpportunityProductEnum.SELLING_PRICE.getAttr(), entity.getData().get(OpportunityProductEnum.SELLING_PRICE.getAttr()));
                    productItemObj.put(OpportunityProductEnum.SELL_TOTAL.getAttr(), Arith.mul(entity.getData().getDouble(OpportunityProductEnum.SELLING_PRICE.getAttr()), entity.getBusinessNum()));
                }else {
                    productItemObj.put(OpportunityProductEnum.SELLING_PRICE.getAttr(), entity.getPrice());
                    productItemObj.put(OpportunityProductEnum.SELL_TOTAL.getAttr(), Arith.mul(entity.getPrice(), entity.getProductNum()));
                }
                productItemObj.put(OpportunityProductEnum.MEMO.getAttr(), entity.getMemo());
                //基本单位时直接塞入productUnit
                if (Objects.isNull(entity.getBusinessUnit())){
                    if (Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                        productItemObj.put(ProductEnum.UNIT.getAttr(), groupBaseUnitStringMap.getOrDefault(productItemObj.getString(ProductEnum.UNIT.getAttr()), new MultiUnitItemPoJo()).getBaseValue());
                        entity.setProductUnit(productItemObj.getString(ProductEnum.UNIT.getAttr()));
                    }
                    productItemObj.put(SelectProductEnum.NUM.getAttr(), entity.getProductNum());
                }else {
                    productItemObj.put(ProductEnum.UNIT.getAttr(), entity.getBusinessUnit());
                    productItemObj.put(SelectProductEnum.NUM.getAttr(), entity.getBusinessNum());
                }
                if(Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), entity.getProductUnit());
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(),  entity.getProductNum());
                }else {
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), "");
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(), "");
                }
                productArray.add(productItemObj);
            }
            formDataObj.put(productAttr, productArray);
        }
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        String corpid = importFormDataDTO.getCorpid();
        formDataAddDTO.setSerialNo("");
        JSONObject dataJson = new JSONObject();
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);

        FieldAttrEntityForImport linkCustomerIdAttr = null;
        for (FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList) {
            if (Objects.equals(fieldAttrEntityForImport.getAttr(), SalesOpportunityEnum.CUSTOMER_NAME.getAttr())) {
                linkCustomerIdAttr = fieldAttrEntityForImport;
                break;
            }
        }

        Long linkCustomerId = 0L;
        if (Objects.nonNull(linkCustomerIdAttr)) {
            linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, linkCustomerIdAttr);
        }

        for (FieldAttrEntityForImport fieldAttr : fieldAttrList) {
            String attr = fieldAttr.getAttr();
            Integer fieldType = fieldAttr.getFieldType();
            String attrName = fieldAttr.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, SalesOpportunityEnum.PRODUCTS.getAttr())) {
                importHelper.formatCommonProduct(titlePojoList, dataJson, rowValueList, fieldAttr, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), corpid);
            } else if (Objects.equals(attr, SalesOpportunityEnum.CUSTOMER_NAME.getAttr())) {

            } else if (Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType())) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttr, dataJson);
            } else {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    continue;
                }
                if (ImportHelper.commonHandleFieldType.contains(fieldAttr.getFieldType())) {
                    importHelper.formatCommonField(dataJson, fieldAttr, cellValue);
                    if (Objects.equals(fieldAttr.getAttr(), SalesOpportunityEnum.SALE_STAGE.getAttr())) {
                        if (StringUtil.isNotEmpty(dataJson.getString(attr))) {
                            dataJson.put(attr, dataJson.getString(attr));
                        }
                        String stageCode = dataJson.getString(attr);
                        SaleStageEntity saleStageEntity = null;
                        if (StringUtil.isNotEmpty(stageCode)) {
                            saleStageEntity = saleStageModel.getByCode(corpid, importFormDataDTO.getFormId(), stageCode);
                        }
                        if (Objects.nonNull(saleStageEntity) && Objects.equals(saleStageEntity.getType(), StageTypeEnum.FAIL_STAGE.getType())) {
                            // 流失原因必填
                            List<ItemPoJo> dictionaryList4Saas = dataDictionaryModel.getDictionaryList4Saas(DictionaryEnum.SALE_STAGE_WASTAGE, importFormDataDTO.getCorpid(), importFormDataDTO.getFormId());
                            if (!dictionaryList4Saas.isEmpty()) {
                                dataJson.put(SalesOpportunityEnum.WASTAGE.getAttr(), dictionaryList4Saas.get(0).getValue());
                            }
                            for (CellValuePojo cellValuePojo : cellValueList) {
                                if (Objects.equals(cellValuePojo.getTitle(), SalesOpportunityEnum.WASTAGE_MEMO.getAttrName())) {
                                    dataJson.put(SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), cellValueList.get(cellValuePojo.getColumnIndex()).getValue());
                                }
                            }
                        }
                    }
                } else {
                    if (Objects.equals(attr, SalesOpportunityEnum.CONTACT_NAME.getAttr())) {
                        importHelper.formatRelyBusiness(linkCustomerId, dataJson, fieldAttr, cellValue, ContactEnum.CUSTOMER_NAME.getAttr());
                    } else if (Objects.equals(attr, SalesOpportunityEnum.DECISION_MAKER.getAttr())) {
                        importHelper.formatMultiRelyBusiness(linkCustomerId, dataJson, fieldAttr, cellValue, ContactEnum.CUSTOMER_NAME.getAttr());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType())) {
                        formDataAddDTO.setSerialNo(cellValue.toString());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                        importHelper.formatLinkData(cellValue, fieldAttr, dataJson);
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                        importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttr, dataJson);
                    } else {
                        dataJson.put(attr, cellValue);
                    }
                }
            }
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    @Override
    public List<PaasFormDataEntityExt> getOpportunityEsDataListByCustomerId(String corpid, Long customerId) throws XbbException {
        return opportunityModel.getOpportunityListByLinkId(corpid, customerId, SalesOpportunityEnum.CUSTOMER_NAME, PaasFormDataEntityExt.class);
    }

    @Override
    public void dataConsistencyUpdateCustomer(String corpid, Long customerId, String customerName) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(SalesOpportunityEnum.getEsAttr4Keyword(SalesOpportunityEnum.CUSTOMER_NAME), customerId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OPPORTUNITY, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<OpportunityEntityExt> opportunityEntityExtList = opportunityModel.findEntitys(param);

            if (Objects.nonNull(opportunityEntityExtList) && !opportunityEntityExtList.isEmpty()) {
                List<OpportunityUpdateDTO> opportunityUpdateDTOList = new ArrayList<>();
                for (OpportunityEntityExt entityExt : opportunityEntityExtList) {
                    OpportunityUpdateDTO opportunityUpdateDTO = new OpportunityUpdateDTO();
                    opportunityUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(SalesOpportunityEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), customerName);
                    opportunityUpdateDTO.setData(data);
                    opportunityUpdateDTOList.add(opportunityUpdateDTO);
                }
                OpportunityUpdateBatchDTO opportunityUpdateBatchDTO = new OpportunityUpdateBatchDTO();
                opportunityUpdateBatchDTO.setCorpid(corpid);
                opportunityUpdateBatchDTO.setOpportunityList(opportunityUpdateDTOList);
                updateBatch(opportunityUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("OpportunityServiceImpl.dataConsistencyUpdateCustomer 出错， corpid=" + corpid + "  customerId=" + customerId + " customerName=" + customerName, e);
        }
    }

    @Override
    public void dataConsistencyUpdateCompetitor(String corpid, Long competitorId, String competitorName) throws XbbException {
        try {
            Map<String,Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put(StringConstant.CORPID,corpid);
            params.put("competitorId",competitorId);
            params.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            List<CompetitorAnalysisEntity> competitorAnalysisEntityList = competitorAnalysisModel.findEntitys(params);
            if(CollectionUtils.isEmpty(competitorAnalysisEntityList)){
                return;
            }
            Set<Long> oppotunityIdSet = new HashSet<>();
            competitorAnalysisEntityList.forEach(item->{
                Long oppotunityId = item.getOppotunityId();
                oppotunityIdSet.add(oppotunityId);
            });

            List<OpportunityEntityExt> opportunityEntityExtList = opportunityModel.getByKeysWithoutSub(oppotunityIdSet, corpid);
            if (Objects.nonNull(opportunityEntityExtList) && !opportunityEntityExtList.isEmpty()) {
                List<OpportunityUpdateDTO> opportunityUpdateDTOList = new ArrayList<>();
                for (OpportunityEntityExt entityExt : opportunityEntityExtList) {
                    JSONObject data = entityExt.getData();
                    List<Long> linkCompetitorIdjsonArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, SalesOpportunityEnum.LINK_COMPETITOR.getAttr(), new JSONArray()).toJavaList(Long.class);
                    List<String> linkCompetitorNameArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, SalesOpportunityEnum.LINK_COMPETITOR_LINK_TEXT.getAttr(), new JSONArray()).toJavaList(String.class);
                    Long winCompetitorId = FastJsonHelper.getLongFromFormData(data, SalesOpportunityEnum.WIN_COMPETITOR.getAttr());
                    for (int i = 0; i < linkCompetitorIdjsonArray.size(); i++) {
                        Long cid = linkCompetitorIdjsonArray.get(i);
                        if (Objects.equals(cid, competitorId)) {
                            linkCompetitorNameArray.set(i, competitorName);
                        }
                    }
                    OpportunityUpdateDTO opportunityUpdateDTO = new OpportunityUpdateDTO();
                    opportunityUpdateDTO.setId(entityExt.getId());
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(SalesOpportunityEnum.LINK_COMPETITOR_LINK_TEXT.getAttr(), linkCompetitorNameArray);
                    if(winCompetitorId!=null && winCompetitorId==competitorId){
                        jsonObject.put(SalesOpportunityEnum.WIN_COMPETITOR_LINK_TEXT.getAttr(), competitorName);
                    }
                    opportunityUpdateDTO.setData(jsonObject);
                    opportunityUpdateDTOList.add(opportunityUpdateDTO);
                }
                OpportunityUpdateBatchDTO opportunityUpdateBatchDTO = new OpportunityUpdateBatchDTO();
                opportunityUpdateBatchDTO.setCorpid(corpid);
                opportunityUpdateBatchDTO.setOpportunityList(opportunityUpdateDTOList);
                updateBatch(opportunityUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("OpportunityServiceImpl.dataConsistencyUpdateCompetitor 出错， corpid=" + corpid + "  competitorId=" + competitorId + " competitorName=" + competitorName, e);
        }
    }

    @Override
    public void dataConsistencyUpdateContact(String corpid, Long contactId, String contactName) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(SalesOpportunityEnum.getEsAttr4Keyword(SalesOpportunityEnum.CONTACT_NAME), contactId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OPPORTUNITY, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<OpportunityEntityExt> opportunityEntityExtList = opportunityModel.findEntitys(param);

            if (Objects.nonNull(opportunityEntityExtList) && !opportunityEntityExtList.isEmpty()) {
                List<OpportunityUpdateDTO> opportunityUpdateDTOList = new ArrayList<>();
                for (OpportunityEntityExt entityExt : opportunityEntityExtList) {
                    OpportunityUpdateDTO opportunityUpdateDTO = new OpportunityUpdateDTO();
                    opportunityUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(SalesOpportunityEnum.CONTACT_NAME_LINK_TEXT.getAttr(), contactName);
                    opportunityUpdateDTO.setData(data);
                    opportunityUpdateDTOList.add(opportunityUpdateDTO);
                }
                OpportunityUpdateBatchDTO opportunityUpdateBatchDTO = new OpportunityUpdateBatchDTO();
                opportunityUpdateBatchDTO.setCorpid(corpid);
                opportunityUpdateBatchDTO.setOpportunityList(opportunityUpdateDTOList);
                updateBatch(opportunityUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("OpportunityServiceImpl.dataConsistencyUpdateContact 出错， corpid=" + corpid + "  contactId=" + contactId + "  contactName=" + contactName, e);
        }
    }

    @Override
    public List<AggSumVO> aggAvgByField(List<AggSumVO> numCountList, FormDataSummaryDTO formDataSummaryDTO, List<AggSumDTO> aggAvgFieldList) throws XbbException {
        List<AggSumVO> aggAvgResultList = new ArrayList<>();
        if (numCountList.isEmpty()) {
            return aggAvgResultList;
        }
        Map<String, AggSumVO> numListMap = new HashMap<>(numCountList.size());
        numCountList.forEach((item)->{
            numListMap.put(item.getAttr(), item);
        });
        for (AggSumDTO item : aggAvgFieldList) {
            String attr = item.getAttr();
            AggSumVO aggSumVO = new AggSumVO();
            aggSumVO.setAttr(attr);
            aggSumVO.setName(item.getName());
            Integer accuracy = item.getFieldAttrEntity().getAccuracy();
            if (SalesOpportunityEnum.GROSS_PROFIT_RATE.getAttr().equals(attr)) {
                AggSumVO grossProfitTotalVO = numListMap.get(SalesOpportunityEnum.GROSS_PROFIT.getAttr());
                AggSumVO estimateAmountVO = numListMap.get(SalesOpportunityEnum.ESTIMATE_AMOUNT.getAttr());
                if ((grossProfitTotalVO == null) || (estimateAmountVO == null)) {
                    continue;
                }
                Double grossProfitTotal = Double.parseDouble(grossProfitTotalVO.getValue().toString());
                Double estimateAmount = Double.parseDouble(estimateAmountVO.getValue().toString());
                // 机会毛利率汇总 = 机会毛利的汇总 / 预计金额汇总
                Double grossProfitRate = estimateAmount == 0D ? 0D :Arith.div( grossProfitTotal, estimateAmount) * 100;
                String value = attrDecimalPrecisionHelper.formatMoneyPrecision(grossProfitRate, accuracy);
                aggSumVO.setValue(value + "%");
            }
            aggAvgResultList.add(aggSumVO);
        }
        return aggAvgResultList;
    }

    @Override
    public void updateRollback(List<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", idIn);
        param.put(StringConstant.CORPID, corpid);
        List<OpportunityEntityExt> communicateList = opportunityModel.findEntitysWithoutSub(param);
        if (Objects.nonNull(communicateList)) {
            for (OpportunityEntityExt item : communicateList) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(item, paasFormDataEntity);
                proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_OPPORTUNITY);
            }
        }
    }

    @Override
    public ProductSummaryVO summaryProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        // 获取参数
        String corpid = businessProductListDTO.getCorpid();
        Long dataId = businessProductListDTO.getDataId();

        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("opportunityId", dataId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put("columns", "product_num, price, business_num, price_data");
        List<OpportunityProductEntity> opportunityProductEntities = opportunityProductModel.findEntitys(modelMap);

        PaasFormDataEntityExt opportunity = opportunityModel.getByKey(dataId, corpid);
        if (Objects.isNull(opportunity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }

        ProductSummaryVO businessProductListVO = new ProductSummaryVO();

        PaasFormExplainEntity opportunityExplain = paasFormExplainModel.getByFormId(opportunity.getFormId(), corpid);
        if (Objects.isNull(opportunityExplain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(opportunityExplain.getExplains());

        Boolean hidePrice = false;
        // 关联产品字段
        FieldAttrEntity productField = explainMap.get(SalesOpportunityEnum.PRODUCTS.getAttr());
        FieldAttrEntity productTotalField = new FieldAttrEntity();
        if (Objects.nonNull(productField)) {
            Map<Integer, List<UserTeamEntity>> userTeamMap = userTeamService.getUserTeam(dataId, corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
            List<String> ownerIds = new ArrayList<>();
            List<String> coUserIds = new ArrayList<>();
            for (Map.Entry<Integer, List<UserTeamEntity>> entry : userTeamMap.entrySet()) {
                if (Objects.equals(entry.getKey(), BasicConstant.MAIN_USER)) {
                    entry.getValue().forEach(team -> ownerIds.add(team.getUserId()));
                } else if (Objects.equals(entry.getKey(), BasicConstant.COOP_USER)) {
                    entry.getValue().forEach(team -> coUserIds.add(team.getUserId()));
                }
            }
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(businessProductListDTO, handlerExplainDTO);
            handlerExplainDTO.setOwnerId(ownerIds);
            handlerExplainDTO.setCoUserId(coUserIds);
            handlerExplainDTO.setCreatorId(opportunity.getCreatorId());
            SubFormPoJo subForm = productField.getSubForm();
            List<FieldAttrEntity> fieldAttrEntityList = new ArrayList<>();
            if (Objects.nonNull(subForm.getItems())) {
                fieldAttrEntityList = (List<FieldAttrEntity>) subForm.getItems();
            }
            for (FieldAttrEntity fieldAttrEntity : fieldAttrEntityList) {
                if (Objects.equals(fieldAttrEntity.getAttr(), OpportunityProductEnum.SELLING_PRICE.getAttr())) {
                    productTotalField = fieldAttrEntity;
                    if (ExplainUtil.isFieldNeedHide(fieldAttrEntity, handlerExplainDTO)) {
                        hidePrice = true;
                    }
                }
            }
        }

        // 产品合计
        Double num = 0D;
        Double totalAmount = 0D;
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_PRICE,ProductEnum.PRICE.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        for (OpportunityProductEntity productEntity : opportunityProductEntities) {
            Double productNum = productEntity.getProductNum() != null ? productEntity.getProductNum(): 0D;
            Double price = productEntity.getPrice() == null ? 0D : productEntity.getPrice();
            if (Objects.nonNull(productEntity.getPriceData()) && !productEntity.getPriceData().isEmpty()) {
                totalAmount = Arith.add(totalAmount, Arith.mul(productEntity.getBusinessNum(), productEntity.getPriceData().getDouble(SelectProductEnum.SELLING_PRICE.getAttr())));
            } else {
                totalAmount = Arith.add(totalAmount, Arith.mul(productNum, price));
            }
            num = Arith.add(num, Objects.nonNull(productEntity.getBusinessNum()) ? productEntity.getBusinessNum() : productNum);
        }
        Integer productSize = opportunityProductEntities.size();
        String summaryInfo = String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_TYPE_NUM), productSize, Arith.doubleToBigDecimal(num));
        businessProductListVO.setSummaryInfo(summaryInfo);

        if (hidePrice) {
            businessProductListVO.setMoneyInfo(String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_MONEY_COUNT), I18nMessageUtil.getMessage(I18nStringConstant.SELL_PRICE), StringConstant.INVISIBLE_VALUE));
        } else {
            businessProductListVO.setMoneyInfo(String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_MONEY_COUNT), I18nMessageUtil.getMessage(I18nStringConstant.SELL_PRICE), AttrDecimalPrecisionHelper.parseThousandth(totalAmount, accuracy)));
        }
        JSONObject others = new JSONObject();
        others.put("hidePrice", hidePrice);
        others.put("amount", totalAmount);
        businessProductListVO.setOthers(others);
        return businessProductListVO;
    }

    /**
     * 数据还原
     * @param corpid
     * @param customerUpdateTimeMap
     * @param customerRestoreBatchDTO
     * @return
     * @throws
     * @author xingxing.xiao
     * @date 2019/09/18 09:21
     */
    @Override
    public void restoreBatch(String corpid, Map<Long, Long> customerUpdateTimeMap, CustomerRestoreBatchDTO customerRestoreBatchDTO) throws XbbException {
        try {
            // 根据客户的 id 和 updateTime 来查询要还原的数据
            List<Long> dataIdList = new ArrayList<>();
            List<String> opportunityNames = new ArrayList<>();
            BoolQueryBuilder booleanQuery = boolQuery();
            booleanQuery.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
            booleanQuery.filter(termQuery(StringConstant.DEL, DelEnum.DELETE.getDel()));
            for (Map.Entry<Long, Long> entry : customerUpdateTimeMap.entrySet()) {
                BoolQueryBuilder shouldQueryBuilder = boolQuery();
                shouldQueryBuilder.filter(termsQuery(SalesOpportunityEnum.getEsAttr4Keyword(SalesOpportunityEnum.CUSTOMER_NAME), entry.getKey().toString()));
                shouldQueryBuilder.filter(rangeQuery(SalesOpportunityEnum.UPDATE_TIME.getAttr()).gte(entry.getValue()));
                booleanQuery.should(shouldQueryBuilder);
            }
            booleanQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            List<String> fieldList = new ArrayList<>();
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            fieldList.add(BasicConstant.SERIAL_NO);
            fieldList.add(SalesOpportunityEnum.getAttrConnectData(SalesOpportunityEnum.NAME));
            List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OPPORTUNITY, booleanQuery, PaasFormDataEntityExt.class, fieldList);
            paasFormDataEntityExtList.forEach(item -> {
                dataIdList.add(item.getId());
                opportunityNames.add(item.getSerialNo() + "（" + item.getData().getString(SalesOpportunityEnum.NAME.getAttr()) + "）");
            });
            if (dataIdList.isEmpty()) {
                return;
            }
            opportunityModel.restoreBatch(dataIdList, corpid, DelEnum.NORMAL.getDel());

            // 日志
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.REVERT_CANCEL;
            String nameStr = StringUtils.join(opportunityNames, "，");
            String userName = customerRestoreBatchDTO.getLoginUserName();
            String userId = customerRestoreBatchDTO.getUserId();
            if(dataIdList.size() > 1){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.SALES_OPPORTUNITY.getName());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.OPPORTUNITY, operateTypeEnum,
                        "", "", memo, customerRestoreBatchDTO.getHttpHeader());
            } else if(Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.OPPORTUNITY, operateTypeEnum,
                        dataIdList.get(0).toString(), nameStr, memo, customerRestoreBatchDTO.getHttpHeader());
            }
        } catch (Exception e){
            LOG.error("OpportunityServiceImpl.restoreBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public DefaultDataVO getOppDefault(DefaultDataDTO businessDataDTO, Map<String, FieldAttrEntity> explainMap, PaasFormDataEntityExt oppEntity) throws XbbException{
        DefaultDataVO defaultDataVO = new DefaultDataVO();
        List<DefaultDataPojo> defaultData = new ArrayList<>();
        String corpid = businessDataDTO.getCorpid();
        Long oppId = oppEntity.getId();
        // 获取关联产品
        List<OpportunityProductEntity> oppProducts = opportunityProductModel.getProductsByOppId(oppId, corpid);
        JSONObject productListObj = new JSONObject();
        JSONArray productList = new JSONArray();
        for (OpportunityProductEntity opportunityProductEntity : oppProducts) {
            JSONObject product = new JSONObject();
            product.put("parentId", opportunityProductEntity.getParentId());
            product.put(StringConstant.SAAS_LINK_BUSINESS_ID, opportunityProductEntity.getProductId());
            product.put(StringConstant.NUM,  opportunityProductEntity.getProductNum());
            product.put(RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), opportunityProductEntity.getDiscount());
            product.put(RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), opportunityProductEntity.getPrice());
            product.put("estimateCost",opportunityProductEntity.getCost());
            productList.add(product);
        }
        productListObj.put(StringConstant.PRODUCT_LIST, productList);
        productListObj.put(BusinessConstant.OTHERS, new JSONObject());
        JSONObject quotationDataList= new JSONObject();
        quotationDataList.put(QuotationEnum.PRODUCT.getAttr(), productListObj);
        SaasAnalysisDataDTO saasAnalysisDataDTO = new SaasAnalysisDataDTO();
        saasAnalysisDataDTO.setForProcess(true);
        saasAnalysisDataDTO.setBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
        BeanUtil.copyProperties(businessDataDTO, saasAnalysisDataDTO);
        quotationService.formatProduct4Show(quotationDataList, saasAnalysisDataDTO);
        JSONObject products = quotationDataList.getJSONObject(QuotationEnum.PRODUCT.getAttr());
        JSONArray productArr = products.getJSONArray(StringConstant.PRODUCT_LIST);

        // 默认产品
        DefaultDataPojo productDefault = new DefaultDataPojo();
        List<Object> defaultProducts = new ArrayList<>();
        defaultProducts.addAll(productArr);
        productDefault.setValue(defaultProducts);
        productDefault.setAttr(QuotationEnum.PRODUCT.getAttr());
        defaultData.add(productDefault);

        defaultDataVO.setDefaultData(defaultData);
        return defaultDataVO;
    }

    @Override
    public Map<Long,String> getOpportunityNameMap(List<Long> handoverIdSet, String corpid) throws XbbException {
        Map<Long,String> opportunityNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (handoverIdSet.isEmpty()){
            return opportunityNameMap;
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),handoverIdSet));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OPPORTUNITY.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, handoverIdSet.size());
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_OPPORTUNITY.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest,PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : esEntities.getContent()){
            opportunityNameMap.put(entity.getDataId(),entity.getData().getString(SalesOpportunityEnum.NAME.getAttr()));
        }
        return opportunityNameMap;
    }

    @Override
    public void autoAdd(String corpid, String userName, String noticeName) throws XbbException{
        LOG.info("---opportunityServiceImp.autoAdd 自动创建机会 start----,corpid-{}-,userName-{}-,noticeName-{}----",corpid,userName,noticeName);
        CompanyEntity companyEntity = companyModel.getByKey(corpid);
        if (companyEntity == null) {
            LOG.error("OpportunityServiceImpl.autoAdd通过corpid找不到公司 corpid为:" + corpid);
            return;
        }

        String proCorpId = ProBaseConfig.getProCorpId();
        String proUserId = ProBaseConfig.getProUserId();
        Long proOppFormId = ProBaseConfig.getProOppFormId();
        Long proCusFormId = ProBaseConfig.getProCusFormId();
        LOG.info("---opportunityServiceImp.autoAdd 模板参数 ----,proCorpId-{}-,proUserId-{}-,proOppFormId-{}-,proCusFormId-{}----",proCorpId,proUserId,proOppFormId,proCusFormId);
        PaasFormExplainEntity oppExplain = paasFormExplainModel.getByFormId(proOppFormId, proCorpId);
        if (Objects.isNull(oppExplain)) {
            LOG.error("opportunityServiceImp.autoAdd通过proOppFormId----" + proOppFormId + "找不到机会模板解释");
            return;
        }
        Long proOppAppId = oppExplain.getAppId();
        Long proOppMenuId = oppExplain.getMenuId();


        BoolQueryBuilder boolQueryBuilder = boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, proCorpId));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery("formId", proCusFormId));
        boolQueryBuilder.filter(termQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.NAME), companyEntity.getCorpName()));
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerIndex.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);

        SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
        if (esEntities == null) {
            LOG.error("opportunityServiceImp.autoAdd 查询客户异常，自动创建结束");
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        List<PaasFormDataEntityExt> content = esEntities.getContent();
        if (CollectionsUtil.isEmpty(content)) {
            LOG.error("opportunityServiceImp.autoAdd 未查询到客户，自动创建结束");
            return;
        }
        PaasFormDataEntityExt paasFormDataEntityExt = content.get(0);
        Long customerId = paasFormDataEntityExt.getDataId();
        JSONObject dataList = new JSONObject();

        JSONObject customerData = paasFormDataEntityExt.getData();
        //机会名称 = 客户名称+申请人名称+通知名称
        String corpName = FastJsonHelper.getStringOrDefaultFromFormData(customerData, CustomerManagementEnum.NAME.getAttr(), "");
        String opportunity = corpName + "-" + userName + "-" + noticeName;
        dataList.put(SalesOpportunityEnum.NAME.getAttr(),opportunity);
        dataList.put(SalesOpportunityEnum.CUSTOMER_NAME.getAttr(), customerId);
        dataList.put(SalesOpportunityEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), corpName);

        //负责人（不存在的话，就取默认的国波的id）
        //formatOwnerId(dataList, customerEntity.getOwnerId());

        //预计金额 0
        dataList.put(SalesOpportunityEnum.ESTIMATE_AMOUNT.getAttr(),0);
        //预计结束时间，创建时间的十五天之后
        Integer estimateEndTime = DateUtil.getInt() + (15*86400);
        dataList.put(SalesOpportunityEnum.ESTIMATE_END_TIME.getAttr(), estimateEndTime);

        String serialNo = "";
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(oppExplain.getExplains(), FieldTypeEnum.SERIALNO.getAlias());
        FieldAttrEntity attrEntity = explainMap.get(FieldTypeEnum.SERIALNO.getAlias());
        if (Objects.isNull(attrEntity)) {
            LOG.error("opportunityServiceImp.autoAdd通过proOppFormId----" + proOppFormId + "找到的机会模板没有流水号字段");
        }
        serialNo = saasSaveHelp.getSerialNo(serialNo, corpid, proOppFormId, attrEntity);

        // 赋默认值
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initOpportunity().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }

        OpportunityEntityExt opportunityEntityExt = new OpportunityEntityExt();
        opportunityEntityExt.setCorpid(proCorpId);
        opportunityEntityExt.setFormId(proOppFormId);
        opportunityEntityExt.setAppId(proOppAppId);
        opportunityEntityExt.setMenuId(proOppMenuId);
        opportunityEntityExt.setSerialNo(serialNo);
        opportunityEntityExt.setOwnerId(proUserId);
        opportunityEntityExt.setDepartmentId(0L);
        opportunityEntityExt.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
        opportunityEntityExt.setData(dataList);
        opportunityEntityExt.setCreatorId(proUserId);
        opportunityEntityExt.setDel(DelEnum.NORMAL.getDel());

        StageProcessEntity stageProcess = stageProcessModel.getEnableStageProcess(opportunityEntityExt.getCorpid(), opportunityEntityExt.getFormId());
        if (Objects.nonNull(stageProcess)) {
            SaleStageEntity stageStage = saleStageModel.getFirstStage(opportunityEntityExt.getCorpid(), opportunityEntityExt.getFormId(), stageProcess.getId());
            if (Objects.nonNull(stageStage)) {
                boolean isNoWorkOrProportionEqualsZero = stageWorkModel.isNoWorkOrProportionEqualsZero(opportunityEntityExt.getCorpid(), opportunityEntityExt.getFormId(), stageProcess.getId(), stageStage.getId(), XbbRefTypeEnum.SALE_STAGE.getCode(), SaasMarkEnum.SAAS.getCode());
                dataList = opportunityEntityExt.getData();
                dataList.put(SalesOpportunityEnum.SALE_STAGE.getAttr(), stageStage.getCode());
                dataList.put(SalesOpportunityEnum.STAGE_PROCESS_ID.getAttr(), stageProcess.getId());
                dataList.put(SalesOpportunityEnum.STAGE_ID.getAttr(), stageStage.getId());
                dataList.put(SalesOpportunityEnum.STAGE_RATIO.getAttr(), isNoWorkOrProportionEqualsZero ? stageStage.getOutProportion() : stageStage.getIntoProportion());
                opportunityModel.insert(opportunityEntityExt);
                // 保存销售机会阶段记录
                OpportunityStageLogEntity saleStageLog = new OpportunityStageLogEntity();
                saleStageLog.setCorpid(opportunityEntityExt.getCorpid());
                saleStageLog.setFormId(opportunityEntityExt.getFormId());
                saleStageLog.setDataId(opportunityEntityExt.getId());
                saleStageLog.setStageCode(stageStage.getCode());
                saleStageLog.setIsNow(1);
                saleStageLog.setIntoTime(DateTimeUtil.getInt());
                saleStageLog.setOutTime(0L);
                saleStageLog.setAddTime(DateTimeUtil.getInt());
                saleStageLog.setUpdateTime(DateTimeUtil.getInt());
                saleStageLog.setDel(0);
                saleStageLog.setStageProcessId(stageProcess.getId());
                saleStageLog.setStageId(stageStage.getId());
                saleStageLog.setStageType(stageStage.getType());
                opportunityStageLogModel.save(saleStageLog);
            } else {
                opportunityModel.insert(opportunityEntityExt);
            }
        } else {
            opportunityModel.insert(opportunityEntityExt);
        }
        LOG.info("opportunityServiceImp.autoAdd 机会创建入库成功");
        boolQueryBuilder = boolQuery();
        sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, proCorpId));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.DATA_ID), paasFormDataEntityExt.getDataId()));
        boolQueryBuilder.filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.IS_MAIN), BasicConstant.ONE));
        IndexTypeEnum idxSaasCustomerTeam =  indexTypeModel.getCustomerTeamIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, idxSaasCustomerTeam.getType()));
        List<PaasFormDataEntity> paasFormDataEntities = esHelper.findByScroll(idxSaasCustomerTeam, boolQueryBuilder, PaasFormDataEntity.class, null);
        if (CollectionsUtil.isEmpty(paasFormDataEntities)) {
            OpportunityUserEntity userEntity = new OpportunityUserEntity();
            userEntity.setCustomerId(customerId);
            userEntity.setIsMain(BasicConstant.ONE);
            userEntity.setUserId(proUserId);
            userEntity.setUserName("");
            userEntity.setUserAvatar("");
            userEntity.setDataId(opportunityEntityExt.getId());
            userEntity.setCorpid(proCorpId);
            userEntity.setDel(DelEnum.NORMAL.getDel());
            opportunityUserModel.save(userEntity);
            LOG.info("opportunityServiceImp.autoAdd 机会创建，关联团队入库成功");
            return;
        }
        List<? extends UserTeamEntity> userTeamEntities = transferSubFormHelper.transferFormDataToUserTeamList(idxSaasCustomerTeam, paasFormDataEntities);
        List<OpportunityUserEntity> opportunityUserEntityList = new ArrayList<>();
        try {
            BeanUtil.copyPropertiesList(userTeamEntities, opportunityUserEntityList, OpportunityUserEntity.class, false);
        } catch (Exception e) {
            LOG.error("自动创建机会添加团队出错");
        }
        opportunityUserEntityList.forEach(item -> {
            item.setCustomerId(customerId);
            item.setDataId(opportunityEntityExt.getId());
        });
        opportunityUserModel.insertBatch(opportunityUserEntityList, false);
        LOG.info("opportunityServiceImp.autoAdd 机会创建，关联团队入库成功");
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        OpportunityUpdateBatchDTO opportunityUpdateBatchDTO = new OpportunityUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, opportunityUpdateBatchDTO);
        List<OpportunityUpdateDTO> opportunityList = new ArrayList<>();
        addBatchList.forEach(item->{
            OpportunityUpdateDTO opportunityUpdateDTO= new OpportunityUpdateDTO();
            opportunityUpdateDTO.setData(item.getData());
            opportunityUpdateDTO.setId(item.getId());
            opportunityList.add(opportunityUpdateDTO);
        });
        opportunityUpdateBatchDTO.setOpportunityList(opportunityList);
        updateBatch(opportunityUpdateBatchDTO);

    }

    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long oppId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        try {
            // 团队保存
            teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), oppId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), true);
//            userTeamService.saveUserTeam(saasFormSaveDTO);
        } catch (XbbException e) {
            LOG.warn("机会保存协同团队", e);
            throw e;
        }
        Runnable runnable = () -> {
            if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(SalesOpportunityEnum.PRODUCTS.getAttr())) {
                try {
                    JSONArray productArray = newPaasFormDataEntity.getData().getJSONArray(SalesOpportunityEnum.PRODUCTS.getAttr());
                    saveProduct2(productArray, corpid, oppId, isNew,newPaasFormDataEntity.getFormId());
                } catch (Exception e) {
                    LOG.error("保存机会关联产品", e);
                }
            }
        };
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long oppId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        try {
            // 团队保存
            teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), oppId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), true);
        } catch (XbbException e) {
            LOG.warn("机会保存协同团队", e);
            throw e;
        }
        Runnable runnable = () -> {
            if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(SalesOpportunityEnum.PRODUCTS.getAttr())) {
                try {
                    JSONArray productArray = newPaasFormDataEntity.getData().getJSONArray(SalesOpportunityEnum.PRODUCTS.getAttr());
                    saveProduct2(productArray, corpid, oppId, isNew,newPaasFormDataEntity.getFormId());
                } catch (Exception e) {
                    LOG.error("保存机会关联产品", e);
                }
            }
        };
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
    }

    /**
     * 处理编辑接口(市场活动统计中间表)
     * @param corpid
     * @param opportunityUpdateList
     */
    public void dealStaticMarket(String corpid, List<OpportunityUpdateDTO> opportunityUpdateList) throws XbbException{
        List<StaticForUpdateDTO> list = new ArrayList<>();
        for (OpportunityUpdateDTO opportunityUpdateDTO : opportunityUpdateList) {
            StaticForUpdateDTO staticForUpdateDTO = new StaticForUpdateDTO();
            BeanUtil.copyProperties(opportunityUpdateDTO, staticForUpdateDTO);
            list.add(staticForUpdateDTO);
        }
        marketActivityForStaticHelp.updateBatchMarketActivity(list, XbbRefTypeEnum.SALES_OPPORTUNITY ,corpid);
    }
}
